From 97909d7619b530df8c4d0a192c87c25e23d96781 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Oct 2021 00:30:27 +0800 Subject: [PATCH 001/352] remove old compiler, add nac3 dependency (WIP) --- artiq/compiler/__init__.py | 0 artiq/compiler/algorithms/__init__.py | 2 - artiq/compiler/algorithms/inline.py | 79 - artiq/compiler/algorithms/unroll.py | 97 - artiq/compiler/analyses/__init__.py | 3 - artiq/compiler/analyses/devirtualization.py | 119 - artiq/compiler/analyses/domination.py | 144 - .../compiler/analyses/invariant_detection.py | 49 - artiq/compiler/asttyped.py | 113 - artiq/compiler/builtins.py | 339 --- artiq/compiler/embedding.py | 1201 -------- artiq/compiler/import_cache.py | 58 - artiq/compiler/iodelay.py | 249 -- artiq/compiler/ir.py | 1504 --------- artiq/compiler/kernel.ld | 53 - artiq/compiler/math_fns.py | 132 - artiq/compiler/module.py | 98 - artiq/compiler/prelude.py | 57 - artiq/compiler/targets.py | 277 -- artiq/compiler/testbench/__init__.py | 21 - artiq/compiler/testbench/embedding.py | 46 - artiq/compiler/testbench/inferencer.py | 103 - artiq/compiler/testbench/irgen.py | 23 - artiq/compiler/testbench/jit.py | 35 - artiq/compiler/testbench/llvmgen.py | 31 - artiq/compiler/testbench/perf.py | 37 - artiq/compiler/testbench/perf_embedding.py | 72 - artiq/compiler/testbench/shlib.py | 30 - artiq/compiler/testbench/signature.py | 44 - artiq/compiler/transforms/__init__.py | 12 - .../compiler/transforms/artiq_ir_generator.py | 2708 ----------------- .../compiler/transforms/asttyped_rewriter.py | 526 ---- .../compiler/transforms/cast_monomorphizer.py | 47 - artiq/compiler/transforms/constant_hoister.py | 43 - .../transforms/dead_code_eliminator.py | 66 - artiq/compiler/transforms/inferencer.py | 1777 ----------- .../compiler/transforms/int_monomorphizer.py | 28 - artiq/compiler/transforms/interleaver.py | 185 -- .../compiler/transforms/iodelay_estimator.py | 327 -- .../compiler/transforms/llvm_ir_generator.py | 1656 ---------- artiq/compiler/transforms/local_demoter.py | 51 - .../compiler/transforms/typedtree_printer.py | 89 - artiq/compiler/types.py | 839 ----- artiq/compiler/validators/__init__.py | 4 - artiq/compiler/validators/constness.py | 58 - artiq/compiler/validators/escape.py | 360 --- artiq/compiler/validators/local_access.py | 187 -- artiq/compiler/validators/monomorphism.py | 41 - artiq/coredevice/core.py | 2 - artiq/frontend/artiq_run.py | 26 +- artiq/test/libartiq_support/lib.rs | 78 - artiq/test/lit/codegen/assign_none.py | 6 - artiq/test/lit/codegen/custom_comparison.py | 13 - artiq/test/lit/codegen/custom_inclusion.py | 13 - .../test/lit/codegen/error_illegal_return.py | 9 - artiq/test/lit/codegen/none_retval.py | 11 - artiq/test/lit/codegen/noop_coercion.py | 4 - .../codegen/unreachable_implicit_return.py | 9 - .../test/lit/codegen/warning_useless_bool.py | 5 - artiq/test/lit/constant_hoisting/device_db.py | 8 - .../lit/constant_hoisting/invariant_load.py | 25 - artiq/test/lit/devirtualization/device_db.py | 8 - artiq/test/lit/devirtualization/function.py | 23 - artiq/test/lit/devirtualization/method.py | 17 - artiq/test/lit/embedding/annotation.py | 22 - artiq/test/lit/embedding/array_math_fns.py | 26 - artiq/test/lit/embedding/array_transpose.py | 22 - artiq/test/lit/embedding/arrays.py | 36 - artiq/test/lit/embedding/async_rpc.py | 15 - artiq/test/lit/embedding/bug_477.py | 20 - .../lit/embedding/class_fn_direct_call.py | 20 - artiq/test/lit/embedding/device_db.py | 8 - artiq/test/lit/embedding/error_attr_absent.py | 16 - .../embedding/error_attr_absent_suggest.py | 16 - .../test/lit/embedding/error_attr_conflict.py | 21 - .../test/lit/embedding/error_attr_constant.py | 18 - artiq/test/lit/embedding/error_attr_unify.py | 17 - artiq/test/lit/embedding/error_host_only.py | 19 - .../embedding/error_kernel_method_no_self.py | 19 - .../error_kernel_method_self_unify.py | 24 - .../embedding/error_name_absent_suggest.py | 13 - .../lit/embedding/error_rpc_annot_return.py | 14 - .../lit/embedding/error_rpc_async_return.py | 15 - .../lit/embedding/error_specialized_annot.py | 19 - .../test/lit/embedding/error_syscall_annot.py | 15 - .../embedding/error_syscall_annot_return.py | 15 - artiq/test/lit/embedding/error_syscall_arg.py | 15 - .../embedding/error_syscall_default_arg.py | 14 - .../lit/embedding/error_syscall_return.py | 14 - artiq/test/lit/embedding/eval.py | 18 - artiq/test/lit/embedding/exception.py | 12 - artiq/test/lit/embedding/fast_math_flags.py | 20 - artiq/test/lit/embedding/fn_ptr_list.py | 15 - .../lit/embedding/function_polymorphism.py | 12 - artiq/test/lit/embedding/inheritance.py | 22 - artiq/test/lit/embedding/invariant_nested.py | 22 - .../lit/embedding/invariant_propagation.py | 26 - artiq/test/lit/embedding/math_fns.py | 31 - .../test/lit/embedding/method_on_instance.py | 22 - artiq/test/lit/embedding/module.py | 11 - .../lit/embedding/rpc_method_polymorphism.py | 14 - artiq/test/lit/embedding/syscall_flags.py | 18 - artiq/test/lit/embedding/tuple.py | 9 - .../test/lit/embedding/warning_invariant_1.py | 22 - .../test/lit/embedding/warning_invariant_2.py | 22 - .../embedding/warning_invariant_missing.py | 20 - artiq/test/lit/escape/const_string.py | 15 - artiq/test/lit/escape/device_db.py | 8 - artiq/test/lit/escape/error_list_aug_asgn.py | 12 - artiq/test/lit/escape/error_mutable_attr.py | 14 - artiq/test/lit/escape/error_string.py | 19 - artiq/test/lit/exceptions/catch.py | 9 - artiq/test/lit/exceptions/catch_all.py | 14 - artiq/test/lit/exceptions/catch_multi.py | 16 - artiq/test/lit/exceptions/catch_outer.py | 16 - artiq/test/lit/exceptions/finally.py | 21 - artiq/test/lit/exceptions/finally_catch.py | 17 - artiq/test/lit/exceptions/finally_raise.py | 23 - artiq/test/lit/exceptions/finally_reraise.py | 22 - artiq/test/lit/exceptions/finally_squash.py | 21 - artiq/test/lit/exceptions/finally_uncaught.py | 12 - artiq/test/lit/exceptions/reraise.py | 16 - artiq/test/lit/exceptions/reraise_update.py | 16 - artiq/test/lit/exceptions/uncaught.py | 7 - artiq/test/lit/inferencer/array_creation.py | 16 - artiq/test/lit/inferencer/builtin_calls.py | 38 - artiq/test/lit/inferencer/cast.py | 8 - artiq/test/lit/inferencer/class.py | 19 - artiq/test/lit/inferencer/coerce.py | 41 - artiq/test/lit/inferencer/coerce_explicit.py | 12 - artiq/test/lit/inferencer/error_array.py | 16 - .../lit/inferencer/error_array_augassign.py | 11 - artiq/test/lit/inferencer/error_array_ops.py | 12 - artiq/test/lit/inferencer/error_assert.py | 6 - .../lit/inferencer/error_builtin_calls.py | 17 - .../inferencer/error_bytes_subscript_mut.py | 5 - artiq/test/lit/inferencer/error_call.py | 23 - artiq/test/lit/inferencer/error_class.py | 10 - .../lit/inferencer/error_class_redefine.py | 8 - artiq/test/lit/inferencer/error_coerce.py | 37 - .../lit/inferencer/error_comprehension.py | 8 - .../test/lit/inferencer/error_control_flow.py | 19 - artiq/test/lit/inferencer/error_exception.py | 14 - artiq/test/lit/inferencer/error_iterable.py | 5 - .../lit/inferencer/error_local_unbound.py | 5 - artiq/test/lit/inferencer/error_locals.py | 35 - artiq/test/lit/inferencer/error_matmult.py | 11 - artiq/test/lit/inferencer/error_method.py | 16 - artiq/test/lit/inferencer/error_return.py | 16 - artiq/test/lit/inferencer/error_str_iter.py | 5 - artiq/test/lit/inferencer/error_subscript.py | 10 - artiq/test/lit/inferencer/error_unify.py | 27 - artiq/test/lit/inferencer/error_with_arity.py | 15 - artiq/test/lit/inferencer/error_with_exn.py | 16 - artiq/test/lit/inferencer/error_with_many.py | 6 - artiq/test/lit/inferencer/error_with_self.py | 17 - artiq/test/lit/inferencer/error_with_var.py | 17 - artiq/test/lit/inferencer/exception.py | 13 - artiq/test/lit/inferencer/gcd.py | 13 - artiq/test/lit/inferencer/if_expr.py | 6 - artiq/test/lit/inferencer/matmult.py | 17 - artiq/test/lit/inferencer/prelude.py | 10 - artiq/test/lit/inferencer/scoping.py | 9 - artiq/test/lit/inferencer/slice.py | 6 - artiq/test/lit/inferencer/unify.py | 82 - artiq/test/lit/inferencer/with.py | 5 - artiq/test/lit/integration/abs.py | 7 - artiq/test/lit/integration/arithmetics.py | 64 - artiq/test/lit/integration/array_binops.py | 98 - artiq/test/lit/integration/array_broadcast.py | 55 - artiq/test/lit/integration/array_creation.py | 50 - artiq/test/lit/integration/array_matmult.py | 25 - artiq/test/lit/integration/array_slice.py | 24 - artiq/test/lit/integration/array_unaryops.py | 11 - artiq/test/lit/integration/attribute.py | 7 - artiq/test/lit/integration/bool.py | 21 - artiq/test/lit/integration/builtin.py | 26 - artiq/test/lit/integration/bytes.py | 5 - artiq/test/lit/integration/class.py | 16 - artiq/test/lit/integration/compare.py | 19 - artiq/test/lit/integration/finally.py | 78 - artiq/test/lit/integration/for.py | 53 - artiq/test/lit/integration/function.py | 11 - artiq/test/lit/integration/if.py | 27 - artiq/test/lit/integration/instance.py | 14 - artiq/test/lit/integration/lambda.py | 10 - artiq/test/lit/integration/list.py | 19 - artiq/test/lit/integration/locals.py | 7 - artiq/test/lit/integration/minmax.py | 7 - artiq/test/lit/integration/print.py | 41 - artiq/test/lit/integration/raise.py | 8 - artiq/test/lit/integration/str.py | 10 - artiq/test/lit/integration/subscript.py | 27 - artiq/test/lit/integration/tuple.py | 13 - artiq/test/lit/integration/while.py | 62 - artiq/test/lit/integration/with.py | 33 - artiq/test/lit/interleaving/control_flow.py | 18 - artiq/test/lit/interleaving/error_inlining.py | 16 - .../error_toplevel_control_flow.py | 17 - artiq/test/lit/interleaving/indirect.py | 28 - artiq/test/lit/interleaving/indirect_arg.py | 28 - artiq/test/lit/interleaving/nonoverlapping.py | 25 - artiq/test/lit/interleaving/overlapping.py | 25 - .../test/lit/interleaving/pure_impure_tie.py | 14 - artiq/test/lit/interleaving/unrolling.py | 23 - artiq/test/lit/iodelay/argument.py | 7 - artiq/test/lit/iodelay/arith.py | 8 - artiq/test/lit/iodelay/call.py | 10 - artiq/test/lit/iodelay/call_subst.py | 13 - artiq/test/lit/iodelay/class.py | 12 - artiq/test/lit/iodelay/error_argument.py | 12 - artiq/test/lit/iodelay/error_arith.py | 21 - .../test/lit/iodelay/error_bad_interleave.py | 8 - artiq/test/lit/iodelay/error_builtinfn.py | 14 - artiq/test/lit/iodelay/error_call_nested.py | 11 - artiq/test/lit/iodelay/error_call_subst.py | 13 - artiq/test/lit/iodelay/error_control_flow.py | 23 - artiq/test/lit/iodelay/error_for.py | 9 - artiq/test/lit/iodelay/error_goto.py | 14 - artiq/test/lit/iodelay/error_iterable.py | 10 - artiq/test/lit/iodelay/error_return.py | 8 - artiq/test/lit/iodelay/error_unify.py | 11 - artiq/test/lit/iodelay/goto.py | 14 - artiq/test/lit/iodelay/interleave.py | 15 - artiq/test/lit/iodelay/linear.py | 12 - artiq/test/lit/iodelay/loop.py | 13 - artiq/test/lit/iodelay/order_invariance.py | 10 - artiq/test/lit/iodelay/range.py | 21 - artiq/test/lit/iodelay/return.py | 17 - artiq/test/lit/iodelay/sequential.py | 8 - artiq/test/lit/lit.cfg | 33 - .../test/lit/local_access/invalid_closure.py | 15 - artiq/test/lit/local_access/invalid_flow.py | 20 - artiq/test/lit/local_access/multiple_asgn.py | 5 - artiq/test/lit/local_access/parallel.py | 6 - artiq/test/lit/local_access/valid.py | 7 - artiq/test/lit/local_demotion/closure.py | 15 - artiq/test/lit/local_demotion/demotion.py | 13 - artiq/test/lit/monomorphism/bug_1242.py | 8 - artiq/test/lit/monomorphism/bug_1252.py | 8 - artiq/test/lit/monomorphism/coercion.py | 10 - artiq/test/lit/monomorphism/integers.py | 8 - artiq/test/lit/monomorphism/round.py | 11 - artiq/test/lit/not.py | 7 - artiq/test/lit/regression/bug_659.py | 17 - artiq/test/lit/regression/device_db.py | 8 - artiq/test/lit/regression/issue_1506.py | 44 - artiq/test/lit/regression/issue_1627.py | 13 - artiq/test/lit/regression/issue_1632.py | 19 - artiq/test/lit/time/advance.py | 8 - artiq/test/lit/time/advance_mu.py | 8 - artiq/test/lit/time/parallel.py | 18 - doc/manual/conf.py | 2 +- flake.lock | 47 +- flake.nix | 123 +- setup.py | 10 +- 256 files changed, 41 insertions(+), 17804 deletions(-) delete mode 100644 artiq/compiler/__init__.py delete mode 100644 artiq/compiler/algorithms/__init__.py delete mode 100644 artiq/compiler/algorithms/inline.py delete mode 100644 artiq/compiler/algorithms/unroll.py delete mode 100644 artiq/compiler/analyses/__init__.py delete mode 100644 artiq/compiler/analyses/devirtualization.py delete mode 100644 artiq/compiler/analyses/domination.py delete mode 100644 artiq/compiler/analyses/invariant_detection.py delete mode 100644 artiq/compiler/asttyped.py delete mode 100644 artiq/compiler/builtins.py delete mode 100644 artiq/compiler/embedding.py delete mode 100644 artiq/compiler/import_cache.py delete mode 100644 artiq/compiler/iodelay.py delete mode 100644 artiq/compiler/ir.py delete mode 100644 artiq/compiler/kernel.ld delete mode 100644 artiq/compiler/math_fns.py delete mode 100644 artiq/compiler/module.py delete mode 100644 artiq/compiler/prelude.py delete mode 100644 artiq/compiler/targets.py delete mode 100644 artiq/compiler/testbench/__init__.py delete mode 100644 artiq/compiler/testbench/embedding.py delete mode 100644 artiq/compiler/testbench/inferencer.py delete mode 100644 artiq/compiler/testbench/irgen.py delete mode 100644 artiq/compiler/testbench/jit.py delete mode 100644 artiq/compiler/testbench/llvmgen.py delete mode 100644 artiq/compiler/testbench/perf.py delete mode 100644 artiq/compiler/testbench/perf_embedding.py delete mode 100644 artiq/compiler/testbench/shlib.py delete mode 100644 artiq/compiler/testbench/signature.py delete mode 100644 artiq/compiler/transforms/__init__.py delete mode 100644 artiq/compiler/transforms/artiq_ir_generator.py delete mode 100644 artiq/compiler/transforms/asttyped_rewriter.py delete mode 100644 artiq/compiler/transforms/cast_monomorphizer.py delete mode 100644 artiq/compiler/transforms/constant_hoister.py delete mode 100644 artiq/compiler/transforms/dead_code_eliminator.py delete mode 100644 artiq/compiler/transforms/inferencer.py delete mode 100644 artiq/compiler/transforms/int_monomorphizer.py delete mode 100644 artiq/compiler/transforms/interleaver.py delete mode 100644 artiq/compiler/transforms/iodelay_estimator.py delete mode 100644 artiq/compiler/transforms/llvm_ir_generator.py delete mode 100644 artiq/compiler/transforms/local_demoter.py delete mode 100644 artiq/compiler/transforms/typedtree_printer.py delete mode 100644 artiq/compiler/types.py delete mode 100644 artiq/compiler/validators/__init__.py delete mode 100644 artiq/compiler/validators/constness.py delete mode 100644 artiq/compiler/validators/escape.py delete mode 100644 artiq/compiler/validators/local_access.py delete mode 100644 artiq/compiler/validators/monomorphism.py delete mode 100644 artiq/test/libartiq_support/lib.rs delete mode 100644 artiq/test/lit/codegen/assign_none.py delete mode 100644 artiq/test/lit/codegen/custom_comparison.py delete mode 100644 artiq/test/lit/codegen/custom_inclusion.py delete mode 100644 artiq/test/lit/codegen/error_illegal_return.py delete mode 100644 artiq/test/lit/codegen/none_retval.py delete mode 100644 artiq/test/lit/codegen/noop_coercion.py delete mode 100644 artiq/test/lit/codegen/unreachable_implicit_return.py delete mode 100644 artiq/test/lit/codegen/warning_useless_bool.py delete mode 100644 artiq/test/lit/constant_hoisting/device_db.py delete mode 100644 artiq/test/lit/constant_hoisting/invariant_load.py delete mode 100644 artiq/test/lit/devirtualization/device_db.py delete mode 100644 artiq/test/lit/devirtualization/function.py delete mode 100644 artiq/test/lit/devirtualization/method.py delete mode 100644 artiq/test/lit/embedding/annotation.py delete mode 100644 artiq/test/lit/embedding/array_math_fns.py delete mode 100644 artiq/test/lit/embedding/array_transpose.py delete mode 100644 artiq/test/lit/embedding/arrays.py delete mode 100644 artiq/test/lit/embedding/async_rpc.py delete mode 100644 artiq/test/lit/embedding/bug_477.py delete mode 100644 artiq/test/lit/embedding/class_fn_direct_call.py delete mode 100644 artiq/test/lit/embedding/device_db.py delete mode 100644 artiq/test/lit/embedding/error_attr_absent.py delete mode 100644 artiq/test/lit/embedding/error_attr_absent_suggest.py delete mode 100644 artiq/test/lit/embedding/error_attr_conflict.py delete mode 100644 artiq/test/lit/embedding/error_attr_constant.py delete mode 100644 artiq/test/lit/embedding/error_attr_unify.py delete mode 100644 artiq/test/lit/embedding/error_host_only.py delete mode 100644 artiq/test/lit/embedding/error_kernel_method_no_self.py delete mode 100644 artiq/test/lit/embedding/error_kernel_method_self_unify.py delete mode 100644 artiq/test/lit/embedding/error_name_absent_suggest.py delete mode 100644 artiq/test/lit/embedding/error_rpc_annot_return.py delete mode 100644 artiq/test/lit/embedding/error_rpc_async_return.py delete mode 100644 artiq/test/lit/embedding/error_specialized_annot.py delete mode 100644 artiq/test/lit/embedding/error_syscall_annot.py delete mode 100644 artiq/test/lit/embedding/error_syscall_annot_return.py delete mode 100644 artiq/test/lit/embedding/error_syscall_arg.py delete mode 100644 artiq/test/lit/embedding/error_syscall_default_arg.py delete mode 100644 artiq/test/lit/embedding/error_syscall_return.py delete mode 100644 artiq/test/lit/embedding/eval.py delete mode 100644 artiq/test/lit/embedding/exception.py delete mode 100644 artiq/test/lit/embedding/fast_math_flags.py delete mode 100644 artiq/test/lit/embedding/fn_ptr_list.py delete mode 100644 artiq/test/lit/embedding/function_polymorphism.py delete mode 100644 artiq/test/lit/embedding/inheritance.py delete mode 100644 artiq/test/lit/embedding/invariant_nested.py delete mode 100644 artiq/test/lit/embedding/invariant_propagation.py delete mode 100644 artiq/test/lit/embedding/math_fns.py delete mode 100644 artiq/test/lit/embedding/method_on_instance.py delete mode 100644 artiq/test/lit/embedding/module.py delete mode 100644 artiq/test/lit/embedding/rpc_method_polymorphism.py delete mode 100644 artiq/test/lit/embedding/syscall_flags.py delete mode 100644 artiq/test/lit/embedding/tuple.py delete mode 100644 artiq/test/lit/embedding/warning_invariant_1.py delete mode 100644 artiq/test/lit/embedding/warning_invariant_2.py delete mode 100644 artiq/test/lit/embedding/warning_invariant_missing.py delete mode 100644 artiq/test/lit/escape/const_string.py delete mode 100644 artiq/test/lit/escape/device_db.py delete mode 100644 artiq/test/lit/escape/error_list_aug_asgn.py delete mode 100644 artiq/test/lit/escape/error_mutable_attr.py delete mode 100644 artiq/test/lit/escape/error_string.py delete mode 100644 artiq/test/lit/exceptions/catch.py delete mode 100644 artiq/test/lit/exceptions/catch_all.py delete mode 100644 artiq/test/lit/exceptions/catch_multi.py delete mode 100644 artiq/test/lit/exceptions/catch_outer.py delete mode 100644 artiq/test/lit/exceptions/finally.py delete mode 100644 artiq/test/lit/exceptions/finally_catch.py delete mode 100644 artiq/test/lit/exceptions/finally_raise.py delete mode 100644 artiq/test/lit/exceptions/finally_reraise.py delete mode 100644 artiq/test/lit/exceptions/finally_squash.py delete mode 100644 artiq/test/lit/exceptions/finally_uncaught.py delete mode 100644 artiq/test/lit/exceptions/reraise.py delete mode 100644 artiq/test/lit/exceptions/reraise_update.py delete mode 100644 artiq/test/lit/exceptions/uncaught.py delete mode 100644 artiq/test/lit/inferencer/array_creation.py delete mode 100644 artiq/test/lit/inferencer/builtin_calls.py delete mode 100644 artiq/test/lit/inferencer/cast.py delete mode 100644 artiq/test/lit/inferencer/class.py delete mode 100644 artiq/test/lit/inferencer/coerce.py delete mode 100644 artiq/test/lit/inferencer/coerce_explicit.py delete mode 100644 artiq/test/lit/inferencer/error_array.py delete mode 100644 artiq/test/lit/inferencer/error_array_augassign.py delete mode 100644 artiq/test/lit/inferencer/error_array_ops.py delete mode 100644 artiq/test/lit/inferencer/error_assert.py delete mode 100644 artiq/test/lit/inferencer/error_builtin_calls.py delete mode 100644 artiq/test/lit/inferencer/error_bytes_subscript_mut.py delete mode 100644 artiq/test/lit/inferencer/error_call.py delete mode 100644 artiq/test/lit/inferencer/error_class.py delete mode 100644 artiq/test/lit/inferencer/error_class_redefine.py delete mode 100644 artiq/test/lit/inferencer/error_coerce.py delete mode 100644 artiq/test/lit/inferencer/error_comprehension.py delete mode 100644 artiq/test/lit/inferencer/error_control_flow.py delete mode 100644 artiq/test/lit/inferencer/error_exception.py delete mode 100644 artiq/test/lit/inferencer/error_iterable.py delete mode 100644 artiq/test/lit/inferencer/error_local_unbound.py delete mode 100644 artiq/test/lit/inferencer/error_locals.py delete mode 100644 artiq/test/lit/inferencer/error_matmult.py delete mode 100644 artiq/test/lit/inferencer/error_method.py delete mode 100644 artiq/test/lit/inferencer/error_return.py delete mode 100644 artiq/test/lit/inferencer/error_str_iter.py delete mode 100644 artiq/test/lit/inferencer/error_subscript.py delete mode 100644 artiq/test/lit/inferencer/error_unify.py delete mode 100644 artiq/test/lit/inferencer/error_with_arity.py delete mode 100644 artiq/test/lit/inferencer/error_with_exn.py delete mode 100644 artiq/test/lit/inferencer/error_with_many.py delete mode 100644 artiq/test/lit/inferencer/error_with_self.py delete mode 100644 artiq/test/lit/inferencer/error_with_var.py delete mode 100644 artiq/test/lit/inferencer/exception.py delete mode 100644 artiq/test/lit/inferencer/gcd.py delete mode 100644 artiq/test/lit/inferencer/if_expr.py delete mode 100644 artiq/test/lit/inferencer/matmult.py delete mode 100644 artiq/test/lit/inferencer/prelude.py delete mode 100644 artiq/test/lit/inferencer/scoping.py delete mode 100644 artiq/test/lit/inferencer/slice.py delete mode 100644 artiq/test/lit/inferencer/unify.py delete mode 100644 artiq/test/lit/inferencer/with.py delete mode 100644 artiq/test/lit/integration/abs.py delete mode 100644 artiq/test/lit/integration/arithmetics.py delete mode 100644 artiq/test/lit/integration/array_binops.py delete mode 100644 artiq/test/lit/integration/array_broadcast.py delete mode 100644 artiq/test/lit/integration/array_creation.py delete mode 100644 artiq/test/lit/integration/array_matmult.py delete mode 100644 artiq/test/lit/integration/array_slice.py delete mode 100644 artiq/test/lit/integration/array_unaryops.py delete mode 100644 artiq/test/lit/integration/attribute.py delete mode 100644 artiq/test/lit/integration/bool.py delete mode 100644 artiq/test/lit/integration/builtin.py delete mode 100644 artiq/test/lit/integration/bytes.py delete mode 100644 artiq/test/lit/integration/class.py delete mode 100644 artiq/test/lit/integration/compare.py delete mode 100644 artiq/test/lit/integration/finally.py delete mode 100644 artiq/test/lit/integration/for.py delete mode 100644 artiq/test/lit/integration/function.py delete mode 100644 artiq/test/lit/integration/if.py delete mode 100644 artiq/test/lit/integration/instance.py delete mode 100644 artiq/test/lit/integration/lambda.py delete mode 100644 artiq/test/lit/integration/list.py delete mode 100644 artiq/test/lit/integration/locals.py delete mode 100644 artiq/test/lit/integration/minmax.py delete mode 100644 artiq/test/lit/integration/print.py delete mode 100644 artiq/test/lit/integration/raise.py delete mode 100644 artiq/test/lit/integration/str.py delete mode 100644 artiq/test/lit/integration/subscript.py delete mode 100644 artiq/test/lit/integration/tuple.py delete mode 100644 artiq/test/lit/integration/while.py delete mode 100644 artiq/test/lit/integration/with.py delete mode 100644 artiq/test/lit/interleaving/control_flow.py delete mode 100644 artiq/test/lit/interleaving/error_inlining.py delete mode 100644 artiq/test/lit/interleaving/error_toplevel_control_flow.py delete mode 100644 artiq/test/lit/interleaving/indirect.py delete mode 100644 artiq/test/lit/interleaving/indirect_arg.py delete mode 100644 artiq/test/lit/interleaving/nonoverlapping.py delete mode 100644 artiq/test/lit/interleaving/overlapping.py delete mode 100644 artiq/test/lit/interleaving/pure_impure_tie.py delete mode 100644 artiq/test/lit/interleaving/unrolling.py delete mode 100644 artiq/test/lit/iodelay/argument.py delete mode 100644 artiq/test/lit/iodelay/arith.py delete mode 100644 artiq/test/lit/iodelay/call.py delete mode 100644 artiq/test/lit/iodelay/call_subst.py delete mode 100644 artiq/test/lit/iodelay/class.py delete mode 100644 artiq/test/lit/iodelay/error_argument.py delete mode 100644 artiq/test/lit/iodelay/error_arith.py delete mode 100644 artiq/test/lit/iodelay/error_bad_interleave.py delete mode 100644 artiq/test/lit/iodelay/error_builtinfn.py delete mode 100644 artiq/test/lit/iodelay/error_call_nested.py delete mode 100644 artiq/test/lit/iodelay/error_call_subst.py delete mode 100644 artiq/test/lit/iodelay/error_control_flow.py delete mode 100644 artiq/test/lit/iodelay/error_for.py delete mode 100644 artiq/test/lit/iodelay/error_goto.py delete mode 100644 artiq/test/lit/iodelay/error_iterable.py delete mode 100644 artiq/test/lit/iodelay/error_return.py delete mode 100644 artiq/test/lit/iodelay/error_unify.py delete mode 100644 artiq/test/lit/iodelay/goto.py delete mode 100644 artiq/test/lit/iodelay/interleave.py delete mode 100644 artiq/test/lit/iodelay/linear.py delete mode 100644 artiq/test/lit/iodelay/loop.py delete mode 100644 artiq/test/lit/iodelay/order_invariance.py delete mode 100644 artiq/test/lit/iodelay/range.py delete mode 100644 artiq/test/lit/iodelay/return.py delete mode 100644 artiq/test/lit/iodelay/sequential.py delete mode 100644 artiq/test/lit/lit.cfg delete mode 100644 artiq/test/lit/local_access/invalid_closure.py delete mode 100644 artiq/test/lit/local_access/invalid_flow.py delete mode 100644 artiq/test/lit/local_access/multiple_asgn.py delete mode 100644 artiq/test/lit/local_access/parallel.py delete mode 100644 artiq/test/lit/local_access/valid.py delete mode 100644 artiq/test/lit/local_demotion/closure.py delete mode 100644 artiq/test/lit/local_demotion/demotion.py delete mode 100644 artiq/test/lit/monomorphism/bug_1242.py delete mode 100644 artiq/test/lit/monomorphism/bug_1252.py delete mode 100644 artiq/test/lit/monomorphism/coercion.py delete mode 100644 artiq/test/lit/monomorphism/integers.py delete mode 100644 artiq/test/lit/monomorphism/round.py delete mode 100644 artiq/test/lit/not.py delete mode 100644 artiq/test/lit/regression/bug_659.py delete mode 100644 artiq/test/lit/regression/device_db.py delete mode 100644 artiq/test/lit/regression/issue_1506.py delete mode 100644 artiq/test/lit/regression/issue_1627.py delete mode 100644 artiq/test/lit/regression/issue_1632.py delete mode 100644 artiq/test/lit/time/advance.py delete mode 100644 artiq/test/lit/time/advance_mu.py delete mode 100644 artiq/test/lit/time/parallel.py diff --git a/artiq/compiler/__init__.py b/artiq/compiler/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/artiq/compiler/algorithms/__init__.py b/artiq/compiler/algorithms/__init__.py deleted file mode 100644 index 50fc4304b..000000000 --- a/artiq/compiler/algorithms/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .inline import inline -from .unroll import unroll diff --git a/artiq/compiler/algorithms/inline.py b/artiq/compiler/algorithms/inline.py deleted file mode 100644 index ce3e3315f..000000000 --- a/artiq/compiler/algorithms/inline.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -:func:`inline` inlines a call instruction in ARTIQ IR. -The call instruction must have a statically known callee, -it must be second to last in the basic block, and the basic -block must have exactly one successor. -""" - -from .. import types, builtins, iodelay, ir - -def inline(call_insn): - assert isinstance(call_insn, ir.Call) - assert call_insn.static_target_function is not None - assert len(call_insn.basic_block.successors()) == 1 - assert call_insn.basic_block.index(call_insn) == \ - len(call_insn.basic_block.instructions) - 2 - - value_map = {} - source_function = call_insn.static_target_function - target_function = call_insn.basic_block.function - target_predecessor = call_insn.basic_block - target_successor = call_insn.basic_block.successors()[0] - - if builtins.is_none(source_function.type.ret): - target_return_phi = None - else: - target_return_phi = target_successor.prepend(ir.Phi(source_function.type.ret)) - - closure = target_predecessor.insert(ir.GetAttr(call_insn.target_function(), '__closure__'), - before=call_insn) - for actual_arg, formal_arg in zip([closure] + call_insn.arguments(), - source_function.arguments): - value_map[formal_arg] = actual_arg - - for source_block in source_function.basic_blocks: - target_block = ir.BasicBlock([], "i." + source_block.name) - target_function.add(target_block) - value_map[source_block] = target_block - - def mapper(value): - if isinstance(value, ir.Constant): - return value - else: - return value_map[value] - - for source_insn in source_function.instructions(): - target_block = value_map[source_insn.basic_block] - if isinstance(source_insn, ir.Return): - if target_return_phi is not None: - target_return_phi.add_incoming(mapper(source_insn.value()), target_block) - target_insn = ir.Branch(target_successor) - elif isinstance(source_insn, ir.Phi): - target_insn = ir.Phi() - elif isinstance(source_insn, ir.Delay): - target_insn = source_insn.copy(mapper) - target_insn.interval = source_insn.interval.fold(call_insn.arg_exprs) - elif isinstance(source_insn, ir.Loop): - target_insn = source_insn.copy(mapper) - target_insn.trip_count = source_insn.trip_count.fold(call_insn.arg_exprs) - elif isinstance(source_insn, ir.Call): - target_insn = source_insn.copy(mapper) - target_insn.arg_exprs = \ - { arg: source_insn.arg_exprs[arg].fold(call_insn.arg_exprs) - for arg in source_insn.arg_exprs } - else: - target_insn = source_insn.copy(mapper) - target_insn.name = "i." + source_insn.name - value_map[source_insn] = target_insn - target_block.append(target_insn) - - for source_insn in source_function.instructions(): - if isinstance(source_insn, ir.Phi): - target_insn = value_map[source_insn] - for block, value in source_insn.incoming(): - target_insn.add_incoming(value_map[value], value_map[block]) - - target_predecessor.terminator().replace_with(ir.Branch(value_map[source_function.entry()])) - if target_return_phi is not None: - call_insn.replace_all_uses_with(target_return_phi) - call_insn.erase() diff --git a/artiq/compiler/algorithms/unroll.py b/artiq/compiler/algorithms/unroll.py deleted file mode 100644 index 392a31a8c..000000000 --- a/artiq/compiler/algorithms/unroll.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -:func:`unroll` unrolls a loop instruction in ARTIQ IR. -The loop's trip count must be constant. -The loop body must not have any control flow instructions -except for one branch back to the loop head. -The loop body must be executed if the condition to which -the instruction refers is true. -""" - -from .. import types, builtins, iodelay, ir -from ..analyses import domination - -def _get_body_blocks(root, limit): - postorder = [] - - visited = set() - def visit(block): - visited.add(block) - for next_block in block.successors(): - if next_block not in visited and next_block is not limit: - visit(next_block) - postorder.append(block) - - visit(root) - - postorder.reverse() - return postorder - -def unroll(loop_insn): - loop_head = loop_insn.basic_block - function = loop_head.function - assert isinstance(loop_insn, ir.Loop) - assert len(loop_head.predecessors()) == 2 - assert len(loop_insn.if_false().predecessors()) == 1 - assert iodelay.is_const(loop_insn.trip_count) - - trip_count = loop_insn.trip_count.fold().value - if trip_count == 0: - loop_insn.replace_with(ir.Branch(loop_insn.if_false())) - return - - source_blocks = _get_body_blocks(loop_insn.if_true(), loop_head) - source_indvar = loop_insn.induction_variable() - source_tail = loop_insn.if_false() - unroll_target = loop_head - for n in range(trip_count): - value_map = {source_indvar: ir.Constant(n, source_indvar.type)} - - for source_block in source_blocks: - target_block = ir.BasicBlock([], "u{}.{}".format(n, source_block.name)) - function.add(target_block) - value_map[source_block] = target_block - - def mapper(value): - if isinstance(value, ir.Constant): - return value - elif value in value_map: - return value_map[value] - else: - return value - - for source_block in source_blocks: - target_block = value_map[source_block] - for source_insn in source_block.instructions: - if isinstance(source_insn, ir.Phi): - target_insn = ir.Phi() - else: - target_insn = source_insn.copy(mapper) - target_insn.name = "u{}.{}".format(n, source_insn.name) - target_block.append(target_insn) - value_map[source_insn] = target_insn - - for source_block in source_blocks: - for source_insn in source_block.instructions: - if isinstance(source_insn, ir.Phi): - target_insn = value_map[source_insn] - for block, value in source_insn.incoming(): - target_insn.add_incoming(value_map[value], value_map[block]) - - assert isinstance(unroll_target.terminator(), (ir.Branch, ir.Loop)) - unroll_target.terminator().replace_with(ir.Branch(value_map[source_blocks[0]])) - unroll_target = value_map[source_blocks[-1]] - - assert isinstance(unroll_target.terminator(), ir.Branch) - assert len(source_blocks[-1].successors()) == 1 - unroll_target.terminator().replace_with(ir.Branch(source_tail)) - - for source_block in reversed(source_blocks): - for source_insn in reversed(source_block.instructions): - for use in set(source_insn.uses): - if isinstance(use, ir.Phi): - assert use.basic_block == loop_head - use.remove_incoming_value(source_insn) - source_insn.erase() - - for source_block in reversed(source_blocks): - source_block.erase() diff --git a/artiq/compiler/analyses/__init__.py b/artiq/compiler/analyses/__init__.py deleted file mode 100644 index bea15e2ca..000000000 --- a/artiq/compiler/analyses/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .domination import DominatorTree -from .devirtualization import Devirtualization -from .invariant_detection import InvariantDetection diff --git a/artiq/compiler/analyses/devirtualization.py b/artiq/compiler/analyses/devirtualization.py deleted file mode 100644 index 3a35639f2..000000000 --- a/artiq/compiler/analyses/devirtualization.py +++ /dev/null @@ -1,119 +0,0 @@ -""" -:class:`Devirtualizer` performs method resolution at -compile time. - -Devirtualization is implemented using a lattice -with three states: unknown → assigned once → diverges. -The lattice is computed individually for every -variable in scope as well as every -(instance type, field name) pair. -""" - -from pythonparser import algorithm -from .. import asttyped, ir, types - -def _advance(target_map, key, value): - if key not in target_map: - target_map[key] = value # unknown → assigned once - else: - target_map[key] = None # assigned once → diverges - -class FunctionResolver(algorithm.Visitor): - def __init__(self, variable_map): - self.variable_map = variable_map - - self.scope_map = dict() - self.queue = [] - - self.in_assign = False - self.current_scopes = [] - - def finalize(self): - for thunk in self.queue: - thunk() - - def visit_scope(self, node): - self.current_scopes.append(node) - self.generic_visit(node) - self.current_scopes.pop() - - def visit_in_assign(self, node): - self.in_assign = True - self.visit(node) - self.in_assign = False - - def visit_Assign(self, node): - self.visit(node.value) - self.visit_in_assign(node.targets) - - def visit_ForT(self, node): - self.visit(node.iter) - self.visit_in_assign(node.target) - self.visit(node.body) - self.visit(node.orelse) - - def visit_withitemT(self, node): - self.visit(node.context_expr) - self.visit_in_assign(node.optional_vars) - - def visit_comprehension(self, node): - self.visit(node.iter) - self.visit_in_assign(node.target) - self.visit(node.ifs) - - def visit_ModuleT(self, node): - self.visit_scope(node) - - def visit_FunctionDefT(self, node): - _advance(self.scope_map, (self.current_scopes[-1], node.name), node) - self.visit_scope(node) - - def visit_NameT(self, node): - if self.in_assign: - # Just give up if we assign anything at all to a variable, and - # assume it diverges. - _advance(self.scope_map, (self.current_scopes[-1], node.id), None) - else: - # Look up the final value in scope_map and copy it into variable_map. - keys = [(scope, node.id) for scope in reversed(self.current_scopes)] - def thunk(): - for key in keys: - if key in self.scope_map: - self.variable_map[node] = self.scope_map[key] - return - self.queue.append(thunk) - -class MethodResolver(algorithm.Visitor): - def __init__(self, variable_map, method_map): - self.variable_map = variable_map - self.method_map = method_map - - # embedding.Stitcher.finalize generates initialization statements - # of form "constructor.meth = meth_body". - def visit_Assign(self, node): - if node.value not in self.variable_map: - return - - value = self.variable_map[node.value] - for target in node.targets: - if isinstance(target, asttyped.AttributeT): - if types.is_constructor(target.value.type): - instance_type = target.value.type.instance - elif types.is_instance(target.value.type): - instance_type = target.value.type - else: - continue - _advance(self.method_map, (instance_type, target.attr), value) - -class Devirtualization: - def __init__(self): - self.variable_map = dict() - self.method_map = dict() - - def visit(self, node): - function_resolver = FunctionResolver(self.variable_map) - function_resolver.visit(node) - function_resolver.finalize() - - method_resolver = MethodResolver(self.variable_map, self.method_map) - method_resolver.visit(node) diff --git a/artiq/compiler/analyses/domination.py b/artiq/compiler/analyses/domination.py deleted file mode 100644 index e5d96ae39..000000000 --- a/artiq/compiler/analyses/domination.py +++ /dev/null @@ -1,144 +0,0 @@ -""" -:class:`DominatorTree` computes the dominance relation over -control flow graphs. - -See http://www.cs.rice.edu/~keith/EMBED/dom.pdf. -""" - -class GenericDominatorTree: - def __init__(self): - self._assign_names() - self._compute() - - def _traverse_in_postorder(self): - raise NotImplementedError - - def _prev_block_names(self, block): - raise NotImplementedError - - def _assign_names(self): - postorder = self._traverse_in_postorder() - - self._start_name = len(postorder) - 1 - self._block_of_name = postorder - self._name_of_block = {} - for block_name, block in enumerate(postorder): - self._name_of_block[block] = block_name - - def _intersect(self, block_name_1, block_name_2): - finger_1, finger_2 = block_name_1, block_name_2 - while finger_1 != finger_2: - while finger_1 < finger_2: - finger_1 = self._doms[finger_1] - while finger_2 < finger_1: - finger_2 = self._doms[finger_2] - return finger_1 - - def _compute(self): - self._doms = {} - - # Start block dominates itself. - self._doms[self._start_name] = self._start_name - - # We don't yet know what blocks dominate all other blocks. - for block_name in range(self._start_name): - self._doms[block_name] = None - - changed = True - while changed: - changed = False - - # For all blocks except start block, in reverse postorder... - for block_name in reversed(range(self._start_name)): - # Select a new immediate dominator from the blocks we have - # already processed, and remember all others. - # We've already processed at least one previous block because - # of the graph traverse order. - new_idom, prev_block_names = None, [] - for prev_block_name in self._prev_block_names(block_name): - if new_idom is None and self._doms[prev_block_name] is not None: - new_idom = prev_block_name - else: - prev_block_names.append(prev_block_name) - - # Find a common previous block - for prev_block_name in prev_block_names: - if self._doms[prev_block_name] is not None: - new_idom = self._intersect(prev_block_name, new_idom) - - if self._doms[block_name] != new_idom: - self._doms[block_name] = new_idom - changed = True - - def immediate_dominator(self, block): - return self._block_of_name[self._doms[self._name_of_block[block]]] - - def dominators(self, block): - # Blocks that are statically unreachable from entry are considered - # dominated by every other block. - if block not in self._name_of_block: - yield from self._block_of_name - return - - block_name = self._name_of_block[block] - yield self._block_of_name[block_name] - while block_name != self._doms[block_name]: - block_name = self._doms[block_name] - yield self._block_of_name[block_name] - -class DominatorTree(GenericDominatorTree): - def __init__(self, function): - self.function = function - super().__init__() - - def _traverse_in_postorder(self): - postorder = [] - - visited = set() - def visit(block): - visited.add(block) - for next_block in block.successors(): - if next_block not in visited: - visit(next_block) - postorder.append(block) - - visit(self.function.entry()) - - return postorder - - def _prev_block_names(self, block_name): - for block in self._block_of_name[block_name].predecessors(): - # Only return predecessors that are statically reachable from entry. - if block in self._name_of_block: - yield self._name_of_block[block] - -class PostDominatorTree(GenericDominatorTree): - def __init__(self, function): - self.function = function - super().__init__() - - def _traverse_in_postorder(self): - postorder = [] - - visited = set() - def visit(block): - visited.add(block) - for next_block in block.predecessors(): - if next_block not in visited: - visit(next_block) - postorder.append(block) - - for block in self.function.basic_blocks: - if not any(block.successors()): - visit(block) - - postorder.append(None) # virtual exit block - return postorder - - def _prev_block_names(self, block_name): - succ_blocks = self._block_of_name[block_name].successors() - if len(succ_blocks) > 0: - for block in succ_blocks: - yield self._name_of_block[block] - else: - yield self._start_name diff --git a/artiq/compiler/analyses/invariant_detection.py b/artiq/compiler/analyses/invariant_detection.py deleted file mode 100644 index 665c7317b..000000000 --- a/artiq/compiler/analyses/invariant_detection.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -:class:`InvariantDetection` determines which attributes can be safely -marked kernel invariant. -""" - -from pythonparser import diagnostic -from .. import ir, types - -class InvariantDetection: - def __init__(self, engine): - self.engine = engine - - def process(self, functions): - self.attr_locs = dict() - self.attr_written = set() - - for func in functions: - self.process_function(func) - - for key in self.attr_locs: - if key not in self.attr_written: - typ, attr = key - if attr in typ.constant_attributes: - continue - - diag = diagnostic.Diagnostic("note", - "attribute '{attr}' of type '{type}' is never written to; " + - "it could be marked as kernel invariant to potentially increase performance", - {"attr": attr, - "type": typ.name}, - self.attr_locs[key]) - self.engine.process(diag) - - def process_function(self, func): - for block in func.basic_blocks: - for insn in block.instructions: - if not isinstance(insn, (ir.GetAttr, ir.SetAttr)): - continue - if not types.is_instance(insn.object().type): - continue - - key = (insn.object().type, insn.attr) - if isinstance(insn, ir.GetAttr): - if types.is_method(insn.type): - continue - if key not in self.attr_locs and insn.loc is not None: - self.attr_locs[key] = insn.loc - elif isinstance(insn, ir.SetAttr): - self.attr_written.add(key) diff --git a/artiq/compiler/asttyped.py b/artiq/compiler/asttyped.py deleted file mode 100644 index 10b197fa4..000000000 --- a/artiq/compiler/asttyped.py +++ /dev/null @@ -1,113 +0,0 @@ -""" -The typedtree module exports the PythonParser AST enriched with -typing information. -""" - -from pythonparser import ast - -class commontyped(ast.commonloc): - """A mixin for typed AST nodes.""" - - _types = ("type",) - - def _reprfields(self): - return self._fields + self._locs + self._types - -class scoped(object): - """ - :ivar typing_env: (dict with string keys and :class:`.types.Type` values) - map of variable names to variable types - :ivar globals_in_scope: (set of string keys) - set of variables resolved as globals - """ - -# Typed versions of untyped nodes -class argT(ast.arg, commontyped): - pass - -class ClassDefT(ast.ClassDef): - _types = ("constructor_type",) -class FunctionDefT(ast.FunctionDef, scoped): - _types = ("signature_type",) -class QuotedFunctionDefT(FunctionDefT): - """ - :ivar flags: (set of str) Code generation flags (see :class:`ir.Function`). - """ -class ModuleT(ast.Module, scoped): - pass - -class ExceptHandlerT(ast.ExceptHandler): - _fields = ("filter", "name", "body") # rename ast.ExceptHandler.type to filter - _types = ("name_type",) - -class ForT(ast.For): - """ - :ivar trip_count: (:class:`iodelay.Expr`) - :ivar trip_interval: (:class:`iodelay.Expr`) - """ - -class withitemT(ast.withitem): - _types = ("enter_type", "exit_type") - -class SliceT(ast.Slice, commontyped): - pass - -class AttributeT(ast.Attribute, commontyped): - pass -class BinOpT(ast.BinOp, commontyped): - pass -class BoolOpT(ast.BoolOp, commontyped): - pass -class CallT(ast.Call, commontyped): - """ - :ivar iodelay: (:class:`iodelay.Expr`) - :ivar arg_exprs: (dict of str to :class:`iodelay.Expr`) - """ -class CompareT(ast.Compare, commontyped): - pass -class DictT(ast.Dict, commontyped): - pass -class DictCompT(ast.DictComp, commontyped, scoped): - pass -class EllipsisT(ast.Ellipsis, commontyped): - pass -class GeneratorExpT(ast.GeneratorExp, commontyped, scoped): - pass -class IfExpT(ast.IfExp, commontyped): - pass -class LambdaT(ast.Lambda, commontyped, scoped): - pass -class ListT(ast.List, commontyped): - pass -class ListCompT(ast.ListComp, commontyped, scoped): - pass -class NameT(ast.Name, commontyped): - pass -class NameConstantT(ast.NameConstant, commontyped): - pass -class NumT(ast.Num, commontyped): - pass -class SetT(ast.Set, commontyped): - pass -class SetCompT(ast.SetComp, commontyped, scoped): - pass -class StrT(ast.Str, commontyped): - pass -class StarredT(ast.Starred, commontyped): - pass -class SubscriptT(ast.Subscript, commontyped): - pass -class TupleT(ast.Tuple, commontyped): - pass -class UnaryOpT(ast.UnaryOp, commontyped): - pass -class YieldT(ast.Yield, commontyped): - pass -class YieldFromT(ast.YieldFrom, commontyped): - pass - -# Novel typed nodes -class CoerceT(ast.expr, commontyped): - _fields = ('value',) # other_value deliberately not in _fields -class QuoteT(ast.expr, commontyped): - _fields = ('value',) diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py deleted file mode 100644 index 54b25e719..000000000 --- a/artiq/compiler/builtins.py +++ /dev/null @@ -1,339 +0,0 @@ -""" -The :mod:`builtins` module contains the builtin Python -and ARTIQ types, such as int or float. -""" - -from collections import OrderedDict -from . import types - -# Types - -class TNone(types.TMono): - def __init__(self): - super().__init__("NoneType") - -class TBool(types.TMono): - def __init__(self): - super().__init__("bool") - - @staticmethod - def zero(): - return False - - @staticmethod - def one(): - return True - -class TInt(types.TMono): - def __init__(self, width=None): - if width is None: - width = types.TVar() - super().__init__("int", {"width": width}) - - @staticmethod - def zero(): - return 0 - - @staticmethod - def one(): - return 1 - -def TInt32(): - return TInt(types.TValue(32)) - -def TInt64(): - return TInt(types.TValue(64)) - -def _int_printer(typ, printer, depth, max_depth): - if types.is_var(typ["width"]): - return "numpy.int?" - else: - return "numpy.int{}".format(types.get_value(typ.find()["width"])) -types.TypePrinter.custom_printers["int"] = _int_printer - -class TFloat(types.TMono): - def __init__(self): - super().__init__("float") - - @staticmethod - def zero(): - return 0.0 - - @staticmethod - def one(): - return 1.0 - -class TStr(types.TMono): - def __init__(self): - super().__init__("str") - -class TBytes(types.TMono): - def __init__(self): - super().__init__("bytes") - -class TByteArray(types.TMono): - def __init__(self): - super().__init__("bytearray") - -class TList(types.TMono): - def __init__(self, elt=None): - if elt is None: - elt = types.TVar() - super().__init__("list", {"elt": elt}) - -class TArray(types.TMono): - def __init__(self, elt=None, num_dims=1): - if elt is None: - elt = types.TVar() - if isinstance(num_dims, int): - # Make TArray more convenient to instantiate from (ARTIQ) user code. - num_dims = types.TValue(num_dims) - # For now, enforce number of dimensions to be known, as we'd otherwise - # need to implement custom unification logic for the type of `shape`. - # Default to 1 to keep compatibility with old user code from before - # multidimensional array support. - assert isinstance(num_dims.value, int), "Number of dimensions must be resolved" - - super().__init__("array", {"elt": elt, "num_dims": num_dims}) - self.attributes = OrderedDict([ - ("buffer", types._TPointer(elt)), - ("shape", types.TTuple([TInt32()] * num_dims.value)), - ]) - -def _array_printer(typ, printer, depth, max_depth): - return "numpy.array(elt={}, num_dims={})".format( - printer.name(typ["elt"], depth, max_depth), typ["num_dims"].value) -types.TypePrinter.custom_printers["array"] = _array_printer - -class TRange(types.TMono): - def __init__(self, elt=None): - if elt is None: - elt = types.TVar() - super().__init__("range", {"elt": elt}) - self.attributes = OrderedDict([ - ("start", elt), - ("stop", elt), - ("step", elt), - ]) - -class TException(types.TMono): - # All exceptions share the same internal layout: - # * Pointer to the unique global with the name of the exception (str) - # (which also serves as the EHABI type_info). - # * File, line and column where it was raised (str, int, int). - # * Message, which can contain substitutions {0}, {1} and {2} (str). - # * Three 64-bit integers, parameterizing the message (numpy.int64). - - # Keep this in sync with the function ARTIQIRGenerator.alloc_exn. - attributes = OrderedDict([ - ("__name__", TStr()), - ("__file__", TStr()), - ("__line__", TInt32()), - ("__col__", TInt32()), - ("__func__", TStr()), - ("__message__", TStr()), - ("__param0__", TInt64()), - ("__param1__", TInt64()), - ("__param2__", TInt64()), - ]) - - def __init__(self, name="Exception", id=0): - super().__init__(name) - self.id = id - -def fn_bool(): - return types.TConstructor(TBool()) - -def fn_int(): - return types.TConstructor(TInt()) - -def fn_int32(): - return types.TBuiltinFunction("int32") - -def fn_int64(): - return types.TBuiltinFunction("int64") - -def fn_float(): - return types.TConstructor(TFloat()) - -def fn_str(): - return types.TConstructor(TStr()) - -def fn_bytes(): - return types.TConstructor(TBytes()) - -def fn_bytearray(): - return types.TConstructor(TByteArray()) - -def fn_list(): - return types.TConstructor(TList()) - -def fn_array(): - return types.TConstructor(TArray()) - -def fn_Exception(): - return types.TExceptionConstructor(TException("Exception")) - -def fn_IndexError(): - return types.TExceptionConstructor(TException("IndexError")) - -def fn_ValueError(): - return types.TExceptionConstructor(TException("ValueError")) - -def fn_ZeroDivisionError(): - return types.TExceptionConstructor(TException("ZeroDivisionError")) - -def fn_RuntimeError(): - return types.TExceptionConstructor(TException("RuntimeError")) - -def fn_range(): - return types.TBuiltinFunction("range") - -def fn_len(): - return types.TBuiltinFunction("len") - -def fn_round(): - return types.TBuiltinFunction("round") - -def fn_abs(): - return types.TBuiltinFunction("abs") - -def fn_min(): - return types.TBuiltinFunction("min") - -def fn_max(): - return types.TBuiltinFunction("max") - -def fn_make_array(): - return types.TBuiltinFunction("make_array") - -def fn_print(): - return types.TBuiltinFunction("print") - -def fn_kernel(): - return types.TBuiltinFunction("kernel") - -def obj_parallel(): - return types.TBuiltin("parallel") - -def obj_interleave(): - return types.TBuiltin("interleave") - -def obj_sequential(): - return types.TBuiltin("sequential") - -def fn_delay(): - return types.TBuiltinFunction("delay") - -def fn_now_mu(): - return types.TBuiltinFunction("now_mu") - -def fn_delay_mu(): - return types.TBuiltinFunction("delay_mu") - -def fn_at_mu(): - return types.TBuiltinFunction("at_mu") - -def fn_rtio_log(): - return types.TBuiltinFunction("rtio_log") - -# Accessors - -def is_none(typ): - return types.is_mono(typ, "NoneType") - -def is_bool(typ): - return types.is_mono(typ, "bool") - -def is_int(typ, width=None): - if width is not None: - return types.is_mono(typ, "int", width=width) - else: - return types.is_mono(typ, "int") - -def is_int32(typ): - return is_int(typ, types.TValue(32)) - -def is_int64(typ): - return is_int(typ, types.TValue(64)) - -def get_int_width(typ): - if is_int(typ): - return types.get_value(typ.find()["width"]) - -def is_float(typ): - return types.is_mono(typ, "float") - -def is_str(typ): - return types.is_mono(typ, "str") - -def is_bytes(typ): - return types.is_mono(typ, "bytes") - -def is_bytearray(typ): - return types.is_mono(typ, "bytearray") - -def is_numeric(typ): - typ = typ.find() - return isinstance(typ, types.TMono) and \ - typ.name in ('int', 'float') - -def is_list(typ, elt=None): - if elt is not None: - return types.is_mono(typ, "list", elt=elt) - else: - return types.is_mono(typ, "list") - -def is_array(typ, elt=None): - if elt is not None: - return types.is_mono(typ, "array", elt=elt) - else: - return types.is_mono(typ, "array") - -def is_listish(typ, elt=None): - if is_list(typ, elt) or is_array(typ, elt): - return True - elif elt is None: - return is_str(typ) or is_bytes(typ) or is_bytearray(typ) - else: - return False - -def is_range(typ, elt=None): - if elt is not None: - return types.is_mono(typ, "range", {"elt": elt}) - else: - return types.is_mono(typ, "range") - -def is_exception(typ, name=None): - if name is None: - return isinstance(typ.find(), TException) - else: - return isinstance(typ.find(), TException) and \ - typ.name == name - -def is_iterable(typ): - return is_listish(typ) or is_range(typ) - -def get_iterable_elt(typ): - # TODO: Arrays count as listish, but this returns the innermost element type for - # n-dimensional arrays, rather than the n-1 dimensional result of iterating over - # the first axis, which makes the name a bit misleading. - if is_str(typ) or is_bytes(typ) or is_bytearray(typ): - return TInt(types.TValue(8)) - elif types._is_pointer(typ) or is_iterable(typ): - return typ.find()["elt"].find() - else: - assert False - -def is_collection(typ): - typ = typ.find() - return isinstance(typ, types.TTuple) or \ - types.is_mono(typ, "list") - -def is_allocated(typ): - return not (is_none(typ) or is_bool(typ) or is_int(typ) or - is_float(typ) or is_range(typ) or - types._is_pointer(typ) or types.is_function(typ) or - types.is_external_function(typ) or types.is_rpc(typ) or - types.is_method(typ) or types.is_tuple(typ) or - types.is_value(typ)) diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py deleted file mode 100644 index 89866c7c8..000000000 --- a/artiq/compiler/embedding.py +++ /dev/null @@ -1,1201 +0,0 @@ -""" -The :class:`Stitcher` class allows to transparently combine compiled -Python code and Python code executed on the host system: it resolves -the references to the host objects and translates the functions -annotated as ``@kernel`` when they are referenced. -""" - -import os, re, linecache, inspect, textwrap, types as pytypes, numpy -from collections import OrderedDict, defaultdict - -from pythonparser import ast, algorithm, source, diagnostic, parse_buffer -from pythonparser import lexer as source_lexer, parser as source_parser - -from Levenshtein import ratio as similarity, jaro_winkler - -from ..language import core as language_core -from . import types, builtins, asttyped, math_fns, prelude -from .transforms import ASTTypedRewriter, Inferencer, IntMonomorphizer, TypedtreePrinter -from .transforms.asttyped_rewriter import LocalExtractor - - -class SpecializedFunction: - def __init__(self, instance_type, host_function): - self.instance_type = instance_type - self.host_function = host_function - - def __eq__(self, other): - if isinstance(other, tuple): - return (self.instance_type == other[0] or - self.host_function == other[1]) - else: - return (self.instance_type == other.instance_type or - self.host_function == other.host_function) - - def __ne__(self, other): - return not self == other - - def __hash__(self): - return hash((self.instance_type, self.host_function)) - - -class EmbeddingMap: - def __init__(self): - self.object_current_key = 0 - self.object_forward_map = {} - self.object_reverse_map = {} - self.module_map = {} - self.type_map = {} - self.function_map = {} - - # Modules - def store_module(self, module, module_type): - self.module_map[module] = module_type - - def retrieve_module(self, module): - return self.module_map[module] - - def has_module(self, module): - return module in self.module_map - - # Types - def store_type(self, host_type, instance_type, constructor_type): - self._rename_type(instance_type) - self.type_map[host_type] = (instance_type, constructor_type) - - def retrieve_type(self, host_type): - return self.type_map[host_type] - - def has_type(self, host_type): - return host_type in self.type_map - - def _rename_type(self, new_instance_type): - # Generally, user-defined types that have exact same name (which is to say, classes - # defined inside functions) do not pose a problem to the compiler. The two places which - # cannot handle this are: - # 1. {TInstance,TConstructor}.__hash__ - # 2. LLVM type names - # Since handling #2 requires renaming on ARTIQ side anyway, it's more straightforward - # to do it once when embedding (since non-embedded code cannot define classes in - # functions). Also, easier to debug. - n = 0 - for host_type in self.type_map: - instance_type, constructor_type = self.type_map[host_type] - if instance_type.name == new_instance_type.name: - n += 1 - new_instance_type.name = "{}.{}".format(new_instance_type.name, n) - - def attribute_count(self): - count = 0 - for host_type in self.type_map: - instance_type, constructor_type = self.type_map[host_type] - count += len(instance_type.attributes) - count += len(constructor_type.attributes) - return count - - # Functions - def store_function(self, function, ir_function_name): - self.function_map[function] = ir_function_name - - def retrieve_function(self, function): - return self.function_map[function] - - def specialize_function(self, instance_type, host_function): - return SpecializedFunction(instance_type, host_function) - - # Objects - def store_object(self, obj_ref): - obj_id = id(obj_ref) - if obj_id in self.object_reverse_map: - return self.object_reverse_map[obj_id] - - self.object_current_key += 1 - self.object_forward_map[self.object_current_key] = obj_ref - self.object_reverse_map[obj_id] = self.object_current_key - return self.object_current_key - - def retrieve_object(self, obj_key): - return self.object_forward_map[obj_key] - - def iter_objects(self): - for obj_id in self.object_forward_map.keys(): - obj_ref = self.object_forward_map[obj_id] - if isinstance(obj_ref, (pytypes.FunctionType, pytypes.MethodType, - pytypes.BuiltinFunctionType, pytypes.ModuleType, - SpecializedFunction)): - continue - elif isinstance(obj_ref, type): - _, obj_typ = self.type_map[obj_ref] - else: - obj_typ, _ = self.type_map[type(obj_ref)] - yield obj_id, obj_ref, obj_typ - - def has_rpc(self): - return any(filter(lambda x: inspect.isfunction(x) or inspect.ismethod(x), - self.object_forward_map.values())) - - -class ASTSynthesizer: - def __init__(self, embedding_map, value_map, quote_function=None, expanded_from=None): - self.source = "" - self.source_buffer = source.Buffer(self.source, "") - self.embedding_map = embedding_map - self.value_map = value_map - self.quote_function = quote_function - self.expanded_from = expanded_from - self.diagnostics = [] - - def finalize(self): - self.source_buffer.source = self.source - return self.source_buffer - - def _add(self, fragment): - range_from = len(self.source) - self.source += fragment - range_to = len(self.source) - return source.Range(self.source_buffer, range_from, range_to, - expanded_from=self.expanded_from) - - def fast_quote_list(self, value): - elts = [None] * len(value) - is_T = False - if len(value) > 0: - v = value[0] - is_T = True - if isinstance(v, int): - T = int - elif isinstance(v, float): - T = float - elif isinstance(v, numpy.int32): - T = numpy.int32 - elif isinstance(v, numpy.int64): - T = numpy.int64 - else: - is_T = False - if is_T: - for v in value: - if not isinstance(v, T): - is_T = False - break - if is_T: - is_int = T != float - if T == int: - typ = builtins.TInt() - elif T == float: - typ = builtins.TFloat() - elif T == numpy.int32: - typ = builtins.TInt32() - elif T == numpy.int64: - typ = builtins.TInt64() - else: - assert False - text = [repr(elt) for elt in value] - start = len(self.source) - self.source += ", ".join(text) - if is_int: - for i, (v, t) in enumerate(zip(value, text)): - l = len(t) - elts[i] = asttyped.NumT( - n=int(v), ctx=None, type=typ, - loc=source.Range( - self.source_buffer, start, start + l, - expanded_from=self.expanded_from)) - start += l + 2 - else: - for i, (v, t) in enumerate(zip(value, text)): - l = len(t) - elts[i] = asttyped.NumT( - n=v, ctx=None, type=typ, - loc=source.Range( - self.source_buffer, start, start + l, - expanded_from=self.expanded_from)) - start += l + 2 - else: - for index, elt in enumerate(value): - elts[index] = self.quote(elt) - if index < len(value) - 1: - self._add(", ") - return elts - - def quote(self, value): - """Construct an AST fragment equal to `value`.""" - if value is None: - typ = builtins.TNone() - return asttyped.NameConstantT(value=value, type=typ, - loc=self._add(repr(value))) - elif isinstance(value, (bool, numpy.bool_)): - typ = builtins.TBool() - coerced = bool(value) - return asttyped.NameConstantT(value=coerced, type=typ, - loc=self._add(repr(coerced))) - elif value is float: - typ = builtins.fn_float() - return asttyped.NameConstantT(value=None, type=typ, - loc=self._add("float")) - elif value is numpy.int32: - typ = builtins.fn_int32() - return asttyped.NameConstantT(value=None, type=typ, - loc=self._add("numpy.int32")) - elif value is numpy.int64: - typ = builtins.fn_int64() - return asttyped.NameConstantT(value=None, type=typ, - loc=self._add("numpy.int64")) - elif value is numpy.array: - typ = builtins.fn_array() - return asttyped.NameConstantT(value=None, type=typ, - loc=self._add("numpy.array")) - elif value is numpy.full: - typ = builtins.fn_make_array() - return asttyped.NameConstantT(value=None, type=typ, - loc=self._add("numpy.full")) - elif isinstance(value, (int, float)): - if isinstance(value, int): - typ = builtins.TInt() - elif isinstance(value, float): - typ = builtins.TFloat() - return asttyped.NumT(n=value, ctx=None, type=typ, - loc=self._add(repr(value))) - elif isinstance(value, numpy.int32): - typ = builtins.TInt32() - return asttyped.NumT(n=int(value), ctx=None, type=typ, - loc=self._add(repr(value))) - elif isinstance(value, numpy.int64): - typ = builtins.TInt64() - return asttyped.NumT(n=int(value), ctx=None, type=typ, - loc=self._add(repr(value))) - elif isinstance(value, str): - return asttyped.StrT(s=value, ctx=None, type=builtins.TStr(), - loc=self._add(repr(value))) - elif isinstance(value, bytes): - return asttyped.StrT(s=value, ctx=None, type=builtins.TBytes(), - loc=self._add(repr(value))) - elif isinstance(value, bytearray): - quote_loc = self._add('`') - repr_loc = self._add(repr(value)) - unquote_loc = self._add('`') - loc = quote_loc.join(unquote_loc) - - return asttyped.QuoteT(value=value, type=builtins.TByteArray(), loc=loc) - elif isinstance(value, list): - begin_loc = self._add("[") - elts = self.fast_quote_list(value) - end_loc = self._add("]") - return asttyped.ListT(elts=elts, ctx=None, type=builtins.TList(), - begin_loc=begin_loc, end_loc=end_loc, - loc=begin_loc.join(end_loc)) - elif isinstance(value, tuple): - begin_loc = self._add("(") - elts = self.fast_quote_list(value) - end_loc = self._add(")") - return asttyped.TupleT(elts=elts, ctx=None, - type=types.TTuple([e.type for e in elts]), - begin_loc=begin_loc, end_loc=end_loc, - loc=begin_loc.join(end_loc)) - elif isinstance(value, numpy.ndarray): - return self.call(numpy.array, [list(value)], {}) - elif inspect.isfunction(value) or inspect.ismethod(value) or \ - isinstance(value, pytypes.BuiltinFunctionType) or \ - isinstance(value, SpecializedFunction) or \ - isinstance(value, numpy.ufunc): - if inspect.ismethod(value): - quoted_self = self.quote(value.__self__) - function_type = self.quote_function(value.__func__, self.expanded_from) - method_type = types.TMethod(quoted_self.type, function_type) - - dot_loc = self._add('.') - name_loc = self._add(value.__func__.__name__) - loc = quoted_self.loc.join(name_loc) - return asttyped.QuoteT(value=value, type=method_type, - self_loc=quoted_self.loc, loc=loc) - else: # function - function_type = self.quote_function(value, self.expanded_from) - - quote_loc = self._add('`') - repr_loc = self._add(repr(value)) - unquote_loc = self._add('`') - loc = quote_loc.join(unquote_loc) - return asttyped.QuoteT(value=value, type=function_type, loc=loc) - elif isinstance(value, pytypes.ModuleType): - if self.embedding_map.has_module(value): - module_type = self.embedding_map.retrieve_module(value) - else: - module_type = types.TModule(value.__name__, OrderedDict()) - module_type.attributes['__objectid__'] = builtins.TInt32() - self.embedding_map.store_module(value, module_type) - - quote_loc = self._add('`') - repr_loc = self._add(repr(value)) - unquote_loc = self._add('`') - loc = quote_loc.join(unquote_loc) - - self.value_map[module_type].append((value, loc)) - return asttyped.QuoteT(value=value, type=module_type, loc=loc) - else: - quote_loc = self._add('`') - repr_loc = self._add(repr(value)) - unquote_loc = self._add('`') - loc = quote_loc.join(unquote_loc) - - if isinstance(value, type): - typ = value - else: - typ = type(value) - - if self.embedding_map.has_type(typ): - instance_type, constructor_type = self.embedding_map.retrieve_type(typ) - - if hasattr(value, 'kernel_invariants') and \ - value.kernel_invariants != instance_type.constant_attributes: - attr_diff = value.kernel_invariants.difference( - instance_type.constant_attributes) - if len(attr_diff) > 0: - diag = diagnostic.Diagnostic("warning", - "object {value} of type {typ} declares attribute(s) {attrs} as " - "kernel invariant, but other objects of the same type do not; " - "the invariant annotation on this object will be ignored", - {"value": repr(value), - "typ": types.TypePrinter().name(instance_type, max_depth=0), - "attrs": ", ".join(["'{}'".format(attr) for attr in attr_diff])}, - loc) - self.diagnostics.append(diag) - attr_diff = instance_type.constant_attributes.difference( - value.kernel_invariants) - if len(attr_diff) > 0: - diag = diagnostic.Diagnostic("warning", - "object {value} of type {typ} does not declare attribute(s) {attrs} as " - "kernel invariant, but other objects of the same type do; " - "the invariant annotation on other objects will be ignored", - {"value": repr(value), - "typ": types.TypePrinter().name(instance_type, max_depth=0), - "attrs": ", ".join(["'{}'".format(attr) for attr in attr_diff])}, - loc) - self.diagnostics.append(diag) - value.kernel_invariants = value.kernel_invariants.intersection( - instance_type.constant_attributes) - else: - if issubclass(typ, BaseException): - if hasattr(typ, 'artiq_builtin'): - exception_id = 0 - else: - exception_id = self.embedding_map.store_object(typ) - instance_type = builtins.TException("{}.{}".format(typ.__module__, - typ.__qualname__), - id=exception_id) - constructor_type = types.TExceptionConstructor(instance_type) - else: - instance_type = types.TInstance("{}.{}".format(typ.__module__, typ.__qualname__), - OrderedDict()) - instance_type.attributes['__objectid__'] = builtins.TInt32() - constructor_type = types.TConstructor(instance_type) - constructor_type.attributes['__objectid__'] = builtins.TInt32() - instance_type.constructor = constructor_type - - self.embedding_map.store_type(typ, instance_type, constructor_type) - - if hasattr(value, 'kernel_invariants'): - assert isinstance(value.kernel_invariants, set) - instance_type.constant_attributes = value.kernel_invariants - - if isinstance(value, type): - self.value_map[constructor_type].append((value, loc)) - return asttyped.QuoteT(value=value, type=constructor_type, - loc=loc) - else: - self.value_map[instance_type].append((value, loc)) - return asttyped.QuoteT(value=value, type=instance_type, - loc=loc) - - def call(self, callee, args, kwargs, callback=None): - """ - Construct an AST fragment calling a function specified by - an AST node `function_node`, with given arguments. - """ - if callback is not None: - callback_node = self.quote(callback) - cb_begin_loc = self._add("(") - - callee_node = self.quote(callee) - arg_nodes = [] - kwarg_nodes = [] - kwarg_locs = [] - - begin_loc = self._add("(") - for index, arg in enumerate(args): - arg_nodes.append(self.quote(arg)) - if index < len(args) - 1: - self._add(", ") - if any(args) and any(kwargs): - self._add(", ") - for index, kw in enumerate(kwargs): - arg_loc = self._add(kw) - equals_loc = self._add("=") - kwarg_locs.append((arg_loc, equals_loc)) - kwarg_nodes.append(self.quote(kwargs[kw])) - if index < len(kwargs) - 1: - self._add(", ") - end_loc = self._add(")") - - if callback is not None: - cb_end_loc = self._add(")") - - node = asttyped.CallT( - func=callee_node, - args=arg_nodes, - keywords=[ast.keyword(arg=kw, value=value, - arg_loc=arg_loc, equals_loc=equals_loc, - loc=arg_loc.join(value.loc)) - for kw, value, (arg_loc, equals_loc) - in zip(kwargs, kwarg_nodes, kwarg_locs)], - starargs=None, kwargs=None, - type=types.TVar(), iodelay=None, arg_exprs={}, - begin_loc=begin_loc, end_loc=end_loc, star_loc=None, dstar_loc=None, - loc=callee_node.loc.join(end_loc)) - - if callback is not None: - node = asttyped.CallT( - func=callback_node, - args=[node], keywords=[], starargs=None, kwargs=None, - type=builtins.TNone(), iodelay=None, arg_exprs={}, - begin_loc=cb_begin_loc, end_loc=cb_end_loc, star_loc=None, dstar_loc=None, - loc=callback_node.loc.join(cb_end_loc)) - - return node - - -def suggest_identifier(id, names): - sorted_names = sorted(names, key=lambda other: jaro_winkler(id, other), reverse=True) - if len(sorted_names) > 0: - if jaro_winkler(id, sorted_names[0]) > 0.0 and similarity(id, sorted_names[0]) > 0.5: - return sorted_names[0] - -class StitchingASTTypedRewriter(ASTTypedRewriter): - def __init__(self, engine, prelude, globals, host_environment, quote): - super().__init__(engine, prelude) - self.globals = globals - self.env_stack.append(self.globals) - - self.host_environment = host_environment - self.quote = quote - - def visit_arg(self, node): - typ = self._find_name(node.arg, node.loc) - # ignore annotations; these are handled in _quote_function - return asttyped.argT(type=typ, - arg=node.arg, annotation=None, - arg_loc=node.arg_loc, colon_loc=node.colon_loc, loc=node.loc) - - def visit_quoted_function(self, node, function): - extractor = LocalExtractor(env_stack=self.env_stack, engine=self.engine) - extractor.visit(node) - - # We quote the defaults so they end up in the global data in LLVM IR. - # This way there is no "life before main", i.e. they do not have to be - # constructed before the main translated call executes; but the Python - # semantics is kept. - defaults = function.__defaults__ or () - quoted_defaults = [] - for default, default_node in zip(defaults, node.args.defaults): - quoted_defaults.append(self.quote(default, default_node.loc)) - node.args.defaults = quoted_defaults - - node = asttyped.QuotedFunctionDefT( - typing_env=extractor.typing_env, globals_in_scope=extractor.global_, - signature_type=types.TVar(), return_type=types.TVar(), - name=node.name, args=node.args, returns=node.returns, - body=node.body, decorator_list=node.decorator_list, - keyword_loc=node.keyword_loc, name_loc=node.name_loc, - arrow_loc=node.arrow_loc, colon_loc=node.colon_loc, at_locs=node.at_locs, - loc=node.loc) - - try: - self.env_stack.append(node.typing_env) - return self.generic_visit(node) - finally: - self.env_stack.pop() - - def visit_Name(self, node): - typ = super()._try_find_name(node.id) - if typ is not None: - # Value from device environment. - return asttyped.NameT(type=typ, id=node.id, ctx=node.ctx, - loc=node.loc) - else: - # Try to find this value in the host environment and quote it. - if node.id == "print": - return self.quote(print, node.loc) - elif node.id in self.host_environment: - return self.quote(self.host_environment[node.id], node.loc) - else: - names = set() - names.update(self.host_environment.keys()) - for typing_env in reversed(self.env_stack): - names.update(typing_env.keys()) - - suggestion = suggest_identifier(node.id, names) - if suggestion is not None: - diag = diagnostic.Diagnostic("fatal", - "name '{name}' is not bound to anything; did you mean '{suggestion}'?", - {"name": node.id, "suggestion": suggestion}, - node.loc) - self.engine.process(diag) - else: - diag = diagnostic.Diagnostic("fatal", - "name '{name}' is not bound to anything", {"name": node.id}, - node.loc) - self.engine.process(diag) - -class StitchingInferencer(Inferencer): - def __init__(self, engine, value_map, quote): - super().__init__(engine) - self.value_map = value_map - self.quote = quote - self.attr_type_cache = {} - - def _compute_attr_type(self, object_value, object_type, object_loc, attr_name, loc): - if not hasattr(object_value, attr_name): - if attr_name.startswith('_'): - names = set(filter(lambda name: not name.startswith('_'), - dir(object_value))) - else: - names = set(dir(object_value)) - suggestion = suggest_identifier(attr_name, names) - - note = diagnostic.Diagnostic("note", - "attribute accessed here", {}, - loc) - if suggestion is not None: - diag = diagnostic.Diagnostic("error", - "host object does not have an attribute '{attr}'; " - "did you mean '{suggestion}'?", - {"attr": attr_name, "suggestion": suggestion}, - object_loc, notes=[note]) - else: - diag = diagnostic.Diagnostic("error", - "host object does not have an attribute '{attr}'", - {"attr": attr_name}, - object_loc, notes=[note]) - self.engine.process(diag) - return - - # Figure out the ARTIQ type of the value of the attribute. - # We do this by quoting it, as if to serialize. This has some - # overhead (i.e. synthesizing a source buffer), but has the advantage - # of having the host-to-ARTIQ mapping code in only one place and - # also immediately getting proper diagnostics on type errors. - attr_value = getattr(object_value, attr_name) - if (inspect.ismethod(attr_value) and - types.is_instance(object_type) and - # Check that the method is indeed defined on the class, - # and not just this instance. The check is written in - # the inverted form and not as hasattr(type(attr_value)) - # since the method may as well be defined on a superclass. - attr_name not in object_value.__dict__): - # In cases like: - # class c: - # @kernel - # def f(self): pass - # we want f to be defined on the class, not on the instance. - attributes = object_type.constructor.attributes - attr_value = SpecializedFunction(object_type, attr_value.__func__) - else: - attributes = object_type.attributes - - attr_value_type = None - - if isinstance(attr_value, list): - # Fast path for lists of scalars. - IS_FLOAT = 1 - IS_INT32 = 2 - IS_INT64 = 4 - - state = 0 - for elt in attr_value: - if elt.__class__ == float: - state |= IS_FLOAT - elif elt.__class__ == int: - if -2**31 < elt < 2**31-1: - state |= IS_INT32 - elif -2**63 < elt < 2**63-1: - state |= IS_INT64 - else: - state = -1 - break - else: - state = -1 - - if state == IS_FLOAT: - attr_value_type = builtins.TList(builtins.TFloat()) - elif state == IS_INT32: - attr_value_type = builtins.TList(builtins.TInt32()) - elif state == IS_INT64: - attr_value_type = builtins.TList(builtins.TInt64()) - - if attr_value_type is None: - note = diagnostic.Diagnostic("note", - "while inferring a type for an attribute '{attr}' of a host object", - {"attr": attr_name}, - loc) - - with self.engine.context(note): - # Slow path. We don't know what exactly is the attribute value, - # so we quote it only for the error message that may possibly result. - ast = self.quote(attr_value, object_loc.expanded_from) - Inferencer(engine=self.engine).visit(ast) - IntMonomorphizer(engine=self.engine).visit(ast) - attr_value_type = ast.type - - return attributes, attr_value_type - - def _unify_attribute(self, result_type, value_node, attr_name, attr_loc, loc): - # The inferencer can only observe types, not values; however, - # when we work with host objects, we have to get the values - # somewhere, since host interpreter does not have types. - # Since we have categorized every host object we quoted according to - # its type, we now interrogate every host object we have to ensure - # that we can successfully serialize the value of the attribute we - # are now adding at the code generation stage. - object_type = value_node.type.find() - for object_value, object_loc in self.value_map[object_type]: - attr_type_key = (id(object_value), attr_name) - try: - attributes, attr_value_type = self.attr_type_cache[attr_type_key] - except KeyError: - attributes, attr_value_type = \ - self._compute_attr_type(object_value, object_type, object_loc, attr_name, loc) - self.attr_type_cache[attr_type_key] = attributes, attr_value_type - - if attr_name not in attributes: - # We just figured out what the type should be. Add it. - attributes[attr_name] = attr_value_type - else: - # Does this conflict with an earlier guess? - try: - attributes[attr_name].unify(attr_value_type) - except types.UnificationError as e: - printer = types.TypePrinter() - diag = diagnostic.Diagnostic("error", - "host object has an attribute '{attr}' of type {typea}, which is" - " different from previously inferred type {typeb} for the same attribute", - {"typea": printer.name(attr_value_type), - "typeb": printer.name(attributes[attr_name]), - "attr": attr_name}, - object_loc) - self.engine.process(diag) - - super()._unify_attribute(result_type, value_node, attr_name, attr_loc, loc) - - def visit_QuoteT(self, node): - if inspect.ismethod(node.value): - if types.is_rpc(types.get_method_function(node.type)): - return - self._unify_method_self(method_type=node.type, - attr_name=node.value.__func__.__name__, - attr_loc=None, - loc=node.loc, - self_loc=node.self_loc) - -class TypedtreeHasher(algorithm.Visitor): - def generic_visit(self, node): - def freeze(obj): - if isinstance(obj, ast.AST): - return self.visit(obj) - elif isinstance(obj, list): - return hash(tuple(freeze(elem) for elem in obj)) - elif isinstance(obj, types.Type): - return hash(obj.find()) - else: - # We don't care; only types change during inference. - pass - - fields = node._fields - if hasattr(node, '_types'): - fields = fields + node._types - return hash(tuple(freeze(getattr(node, field_name)) for field_name in fields)) - -class Stitcher: - def __init__(self, core, dmgr, engine=None, print_as_rpc=True): - self.core = core - self.dmgr = dmgr - if engine is None: - self.engine = diagnostic.Engine(all_errors_are_fatal=True) - else: - self.engine = engine - - self.name = "" - self.typedtree = [] - self.inject_at = 0 - self.globals = {} - - # We don't want some things from the prelude as they are provided in - # the host Python namespace and gain special meaning when quoted. - self.prelude = prelude.globals() - if print_as_rpc: - self.prelude.pop("print") - self.prelude.pop("array") - - self.functions = {} - - self.embedding_map = EmbeddingMap() - self.value_map = defaultdict(lambda: []) - self.definitely_changed = False - - def stitch_call(self, function, args, kwargs, callback=None): - # We synthesize source code for the initial call so that - # diagnostics would have something meaningful to display to the user. - synthesizer = self._synthesizer(self._function_loc(function.artiq_embedded.function)) - call_node = synthesizer.call(function, args, kwargs, callback) - synthesizer.finalize() - self.typedtree.append(call_node) - - def finalize(self): - inferencer = StitchingInferencer(engine=self.engine, - value_map=self.value_map, - quote=self._quote) - typedtree_hasher = TypedtreeHasher() - - # Iterate inference to fixed point. - old_typedtree_hash = None - old_attr_count = None - while True: - inferencer.visit(self.typedtree) - if self.definitely_changed: - changed = True - self.definitely_changed = False - else: - typedtree_hash = typedtree_hasher.visit(self.typedtree) - attr_count = self.embedding_map.attribute_count() - changed = old_attr_count != attr_count or \ - old_typedtree_hash != typedtree_hash - old_typedtree_hash = typedtree_hash - old_attr_count = attr_count - - if not changed: - break - - # After we've discovered every referenced attribute, check if any kernel_invariant - # specifications refers to ones we didn't encounter. - for host_type in self.embedding_map.type_map: - instance_type, constructor_type = self.embedding_map.type_map[host_type] - if not hasattr(instance_type, "constant_attributes"): - # Exceptions lack user-definable attributes. - continue - - for attribute in instance_type.constant_attributes: - if attribute in instance_type.attributes: - # Fast path; if the ARTIQ Python type has the attribute, then every observed - # value is guaranteed to have it too. - continue - - for value, loc in self.value_map[instance_type]: - if hasattr(value, attribute): - continue - - diag = diagnostic.Diagnostic("warning", - "object {value} of type {typ} declares attribute '{attr}' as " - "kernel invariant, but the instance referenced here does not " - "have this attribute", - {"value": repr(value), - "typ": types.TypePrinter().name(instance_type, max_depth=0), - "attr": attribute}, - loc) - self.engine.process(diag) - - # After we have found all functions, synthesize a module to hold them. - source_buffer = source.Buffer("", "") - self.typedtree = asttyped.ModuleT( - typing_env=self.globals, globals_in_scope=set(), - body=self.typedtree, loc=source.Range(source_buffer, 0, 0)) - - def _inject(self, node): - self.typedtree.insert(self.inject_at, node) - self.inject_at += 1 - - def _synthesizer(self, expanded_from=None): - return ASTSynthesizer(expanded_from=expanded_from, - embedding_map=self.embedding_map, - value_map=self.value_map, - quote_function=self._quote_function) - - def _function_loc(self, function): - if isinstance(function, SpecializedFunction): - function = function.host_function - if hasattr(function, 'artiq_embedded') and function.artiq_embedded.function: - function = function.artiq_embedded.function - - if isinstance(function, str): - return source.Range(source.Buffer(function, ""), 0, 0) - - filename = function.__code__.co_filename - line = function.__code__.co_firstlineno - name = function.__code__.co_name - - source_line = linecache.getline(filename, line).lstrip() - while source_line.startswith("@") or source_line == "": - line += 1 - source_line = linecache.getline(filename, line).lstrip() - - if "" in function.__qualname__: - column = 0 # can't get column of lambda - else: - column = re.search("def", source_line).start(0) - source_buffer = source.Buffer(source_line, filename, line) - return source.Range(source_buffer, column, column) - - def _call_site_note(self, call_loc, fn_kind): - if call_loc: - if fn_kind == 'syscall': - return [diagnostic.Diagnostic("note", - "in system call here", {}, - call_loc)] - elif fn_kind == 'rpc': - return [diagnostic.Diagnostic("note", - "in function called remotely here", {}, - call_loc)] - elif fn_kind == 'kernel': - return [diagnostic.Diagnostic("note", - "in kernel function here", {}, - call_loc)] - else: - assert False - else: - return [] - - def _type_of_param(self, function, loc, param, fn_kind): - if param.annotation is not inspect.Parameter.empty: - # Type specified explicitly. - return self._extract_annot(function, param.annotation, - "argument '{}'".format(param.name), loc, - fn_kind) - elif fn_kind == 'syscall': - # Syscalls must be entirely annotated. - diag = diagnostic.Diagnostic("error", - "system call argument '{argument}' must have a type annotation", - {"argument": param.name}, - self._function_loc(function), - notes=self._call_site_note(loc, fn_kind)) - self.engine.process(diag) - elif fn_kind == 'rpc' and param.default is not inspect.Parameter.empty: - notes = [] - notes.append(diagnostic.Diagnostic("note", - "expanded from here while trying to infer a type for an" - " unannotated optional argument '{argument}' from its default value", - {"argument": param.name}, - self._function_loc(function))) - if loc is not None: - notes.append(self._call_site_note(loc, fn_kind)) - - with self.engine.context(*notes): - # Try and infer the type from the default value. - # This is tricky, because the default value might not have - # a well-defined type in APython. - # In this case, we bail out, but mention why we do it. - ast = self._quote(param.default, None) - Inferencer(engine=self.engine).visit(ast) - IntMonomorphizer(engine=self.engine).visit(ast) - return ast.type - else: - # Let the rest of the program decide. - return types.TVar() - - def _quote_embedded_function(self, function, flags): - # we are now parsing new functions... definitely changed the type - self.definitely_changed = True - - if isinstance(function, SpecializedFunction): - host_function = function.host_function - else: - host_function = function - - if not hasattr(host_function, "artiq_embedded"): - raise ValueError("{} is not an embedded function".format(repr(host_function))) - - # Extract function source. - embedded_function = host_function.artiq_embedded.function - if isinstance(embedded_function, str): - # This is a function to be eval'd from the given source code in string form. - # Mangle the host function's id() into the fully qualified name to make sure - # there are no collisions. - source_code = embedded_function - embedded_function = host_function - filename = "" - module_name = "__eval_{}".format(id(host_function)) - first_line = 1 - else: - source_code = inspect.getsource(embedded_function) - filename = embedded_function.__code__.co_filename - module_name = embedded_function.__globals__['__name__'] - first_line = embedded_function.__code__.co_firstlineno - - # Extract function annotation. - signature = inspect.signature(embedded_function) - loc = self._function_loc(embedded_function) - - arg_types = OrderedDict() - optarg_types = OrderedDict() - for param in signature.parameters.values(): - if param.kind == inspect.Parameter.VAR_POSITIONAL or \ - param.kind == inspect.Parameter.VAR_KEYWORD: - diag = diagnostic.Diagnostic("error", - "variadic arguments are not supported; '{argument}' is variadic", - {"argument": param.name}, - self._function_loc(function), - notes=self._call_site_note(loc, fn_kind='kernel')) - self.engine.process(diag) - - arg_type = self._type_of_param(function, loc, param, fn_kind='kernel') - if param.default is inspect.Parameter.empty: - arg_types[param.name] = arg_type - else: - optarg_types[param.name] = arg_type - - if signature.return_annotation is not inspect.Signature.empty: - ret_type = self._extract_annot(function, signature.return_annotation, - "return type", loc, fn_kind='kernel') - else: - ret_type = types.TVar() - - # Extract function environment. - host_environment = dict() - host_environment.update(embedded_function.__globals__) - cells = embedded_function.__closure__ - cell_names = embedded_function.__code__.co_freevars - host_environment.update({var: cells[index] for index, var in enumerate(cell_names)}) - - # Find out how indented we are. - initial_whitespace = re.search(r"^\s*", source_code).group(0) - initial_indent = len(initial_whitespace.expandtabs()) - - # Parse. - source_buffer = source.Buffer(source_code, filename, first_line) - lexer = source_lexer.Lexer(source_buffer, version=(3, 6), diagnostic_engine=self.engine) - lexer.indent = [(initial_indent, - source.Range(source_buffer, 0, len(initial_whitespace)), - initial_whitespace)] - parser = source_parser.Parser(lexer, version=(3, 6), diagnostic_engine=self.engine) - function_node = parser.file_input().body[0] - - # Mangle the name, since we put everything into a single module. - full_function_name = "{}.{}".format(module_name, host_function.__qualname__) - if isinstance(function, SpecializedFunction): - instance_type = function.instance_type - function_node.name = "_Z{}{}I{}{}Ezz".format(len(full_function_name), full_function_name, - len(instance_type.name), instance_type.name) - else: - function_node.name = "_Z{}{}zz".format(len(full_function_name), full_function_name) - - # Record the function in the function map so that LLVM IR generator - # can handle quoting it. - self.embedding_map.store_function(function, function_node.name) - - # Fill in the function type before typing it to handle recursive - # invocations. - self.functions[function] = types.TFunction(arg_types, optarg_types, ret_type) - - # Rewrite into typed form. - asttyped_rewriter = StitchingASTTypedRewriter( - engine=self.engine, prelude=self.prelude, - globals=self.globals, host_environment=host_environment, - quote=self._quote) - function_node = asttyped_rewriter.visit_quoted_function(function_node, embedded_function) - function_node.flags = flags - - # Add it into our typedtree so that it gets inferenced and codegen'd. - self._inject(function_node) - - # Tie the typing knot. - self.functions[function].unify(function_node.signature_type) - - return function_node - - def _extract_annot(self, function, annot, kind, call_loc, fn_kind): - if annot is None: - annot = builtins.TNone() - - if isinstance(function, SpecializedFunction): - host_function = function.host_function - else: - host_function = function - - if hasattr(host_function, 'artiq_embedded'): - embedded_function = host_function.artiq_embedded.function - else: - embedded_function = host_function - - if isinstance(embedded_function, str): - embedded_function = host_function - - if isinstance(annot, str): - try: - annot = eval(annot, embedded_function.__globals__) - except Exception: - diag = diagnostic.Diagnostic( - "error", - "type annotation for {kind}, {annot}, cannot be evaluated", - {"kind": kind, "annot": repr(annot)}, - self._function_loc(function), - notes=self._call_site_note(call_loc, fn_kind)) - self.engine.process(diag) - - if not isinstance(annot, types.Type): - diag = diagnostic.Diagnostic("error", - "type annotation for {kind}, '{annot}', is not an ARTIQ type", - {"kind": kind, "annot": repr(annot)}, - self._function_loc(function), - notes=self._call_site_note(call_loc, fn_kind)) - self.engine.process(diag) - - return types.TVar() - else: - return annot - - def _quote_syscall(self, function, loc): - signature = inspect.signature(function) - - arg_types = OrderedDict() - optarg_types = OrderedDict() - for param in signature.parameters.values(): - if param.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD: - diag = diagnostic.Diagnostic("error", - "system calls must only use positional arguments; '{argument}' isn't", - {"argument": param.name}, - self._function_loc(function), - notes=self._call_site_note(loc, fn_kind='syscall')) - self.engine.process(diag) - - if param.default is inspect.Parameter.empty: - arg_types[param.name] = self._type_of_param(function, loc, param, - fn_kind='syscall') - else: - diag = diagnostic.Diagnostic("error", - "system call argument '{argument}' must not have a default value", - {"argument": param.name}, - self._function_loc(function), - notes=self._call_site_note(loc, fn_kind='syscall')) - self.engine.process(diag) - - if signature.return_annotation is not inspect.Signature.empty: - ret_type = self._extract_annot(function, signature.return_annotation, - "return type", loc, fn_kind='syscall') - else: - diag = diagnostic.Diagnostic("error", - "system call must have a return type annotation", {}, - self._function_loc(function), - notes=self._call_site_note(loc, fn_kind='syscall')) - self.engine.process(diag) - ret_type = types.TVar() - - function_type = types.TExternalFunction(arg_types, ret_type, - name=function.artiq_embedded.syscall, - flags=function.artiq_embedded.flags) - self.functions[function] = function_type - return function_type - - def _quote_rpc(self, function, loc): - if isinstance(function, SpecializedFunction): - host_function = function.host_function - else: - host_function = function - ret_type = builtins.TNone() - - if isinstance(host_function, pytypes.BuiltinFunctionType): - pass - elif (isinstance(host_function, pytypes.FunctionType) or \ - isinstance(host_function, pytypes.MethodType)): - if isinstance(host_function, pytypes.FunctionType): - signature = inspect.signature(host_function) - else: - # inspect bug? - signature = inspect.signature(host_function.__func__) - if signature.return_annotation is not inspect.Signature.empty: - ret_type = self._extract_annot(host_function, signature.return_annotation, - "return type", loc, fn_kind='rpc') - else: - assert False - - is_async = False - if hasattr(host_function, "artiq_embedded") and \ - "async" in host_function.artiq_embedded.flags: - is_async = True - - if not builtins.is_none(ret_type) and is_async: - note = diagnostic.Diagnostic("note", - "function called here", {}, - loc) - diag = diagnostic.Diagnostic("fatal", - "functions that return a value cannot be defined as async RPCs", {}, - self._function_loc(host_function.artiq_embedded.function), - notes=[note]) - self.engine.process(diag) - - function_type = types.TRPC(ret_type, - service=self.embedding_map.store_object(host_function), - is_async=is_async) - self.functions[function] = function_type - return function_type - - def _quote_function(self, function, loc): - if isinstance(function, SpecializedFunction): - host_function = function.host_function - else: - host_function = function - - if function in self.functions: - return self.functions[function] - - math_type = math_fns.match(function) - if math_type is not None: - self.functions[function] = math_type - elif not hasattr(host_function, "artiq_embedded") or \ - (host_function.artiq_embedded.core_name is None and - host_function.artiq_embedded.portable is False and - host_function.artiq_embedded.syscall is None and - host_function.artiq_embedded.forbidden is False): - self._quote_rpc(function, loc) - elif host_function.artiq_embedded.function is not None: - if host_function.__name__ == "": - note = diagnostic.Diagnostic("note", - "lambda created here", {}, - self._function_loc(host_function.artiq_embedded.function)) - diag = diagnostic.Diagnostic("fatal", - "lambdas cannot be used as kernel functions", {}, - loc, - notes=[note]) - self.engine.process(diag) - - core_name = host_function.artiq_embedded.core_name - if core_name is not None and self.dmgr.get(core_name) != self.core: - note = diagnostic.Diagnostic("note", - "called from this function", {}, - loc) - diag = diagnostic.Diagnostic("fatal", - "this function runs on a different core device '{name}'", - {"name": host_function.artiq_embedded.core_name}, - self._function_loc(host_function.artiq_embedded.function), - notes=[note]) - self.engine.process(diag) - - self._quote_embedded_function(function, - flags=host_function.artiq_embedded.flags) - elif host_function.artiq_embedded.syscall is not None: - # Insert a storage-less global whose type instructs the compiler - # to perform a system call instead of a regular call. - self._quote_syscall(function, loc) - elif host_function.artiq_embedded.forbidden is not None: - diag = diagnostic.Diagnostic("fatal", - "this function cannot be called as an RPC", {}, - self._function_loc(host_function), - notes=self._call_site_note(loc, fn_kind='rpc')) - self.engine.process(diag) - else: - assert False - - return self.functions[function] - - def _quote(self, value, loc): - synthesizer = self._synthesizer(loc) - node = synthesizer.quote(value) - synthesizer.finalize() - if len(synthesizer.diagnostics) > 0: - for warning in synthesizer.diagnostics: - self.engine.process(warning) - return node diff --git a/artiq/compiler/import_cache.py b/artiq/compiler/import_cache.py deleted file mode 100644 index 9300f5c39..000000000 --- a/artiq/compiler/import_cache.py +++ /dev/null @@ -1,58 +0,0 @@ -import sys -import builtins -import linecache -import tokenize -import logging -import importlib.machinery as im - -from artiq.experiment import kernel, portable - - -__all__ = ["install_hook"] - - -logger = logging.getLogger(__name__) - - -cache = dict() -im_exec_module = None -linecache_getlines = None - - -def hook_exec_module(self, module): - im_exec_module(self, module) - if (hasattr(module, "__file__") - # Heuristic to determine if the module may contain ARTIQ kernels. - # This breaks if kernel is not imported the usual way. - and ((getattr(module, "kernel", None) is kernel) - or (getattr(module, "portable", None) is portable))): - fn = module.__file__ - try: - with tokenize.open(fn) as fp: - lines = fp.readlines() - if lines and not lines[-1].endswith("\n"): - lines[-1] += "\n" - cache[fn] = lines - except: - logger.warning("failed to add '%s' to cache", fn, exc_info=True) - else: - logger.debug("added '%s' to cache", fn) - - -def hook_getlines(filename, module_globals=None): - if filename in cache: - return cache[filename] - else: - return linecache_getlines(filename, module_globals) - - -def install_hook(): - global im_exec_module, linecache_getlines - - im_exec_module = im.SourceFileLoader.exec_module - im.SourceFileLoader.exec_module = hook_exec_module - - linecache_getlines = linecache.getlines - linecache.getlines = hook_getlines - - logger.debug("hook installed") diff --git a/artiq/compiler/iodelay.py b/artiq/compiler/iodelay.py deleted file mode 100644 index 6cab8588c..000000000 --- a/artiq/compiler/iodelay.py +++ /dev/null @@ -1,249 +0,0 @@ -""" -The :mod:`iodelay` module contains the classes describing -the statically inferred RTIO delay arising from executing -a function. -""" - -from functools import reduce - -class Expr: - def __add__(lhs, rhs): - assert isinstance(rhs, Expr) - return Add(lhs, rhs) - __iadd__ = __add__ - - def __sub__(lhs, rhs): - assert isinstance(rhs, Expr) - return Sub(lhs, rhs) - __isub__ = __sub__ - - def __mul__(lhs, rhs): - assert isinstance(rhs, Expr) - return Mul(lhs, rhs) - __imul__ = __mul__ - - def __truediv__(lhs, rhs): - assert isinstance(rhs, Expr) - return TrueDiv(lhs, rhs) - __itruediv__ = __truediv__ - - def __floordiv__(lhs, rhs): - assert isinstance(rhs, Expr) - return FloorDiv(lhs, rhs) - __ifloordiv__ = __floordiv__ - - def __ne__(lhs, rhs): - return not (lhs == rhs) - - def free_vars(self): - return set() - - def fold(self, vars=None): - return self - -class Const(Expr): - _priority = 1 - - def __init__(self, value): - assert isinstance(value, (int, float)) - self.value = value - - def __str__(self): - return str(self.value) - - def __eq__(lhs, rhs): - return rhs.__class__ == lhs.__class__ and lhs.value == rhs.value - - def eval(self, env): - return self.value - -class Var(Expr): - _priority = 1 - - def __init__(self, name): - assert isinstance(name, str) - self.name = name - - def __str__(self): - return self.name - - def __eq__(lhs, rhs): - return rhs.__class__ == lhs.__class__ and lhs.name == rhs.name - - def free_vars(self): - return {self.name} - - def fold(self, vars=None): - if vars is not None and self.name in vars: - return vars[self.name] - else: - return self - -class Conv(Expr): - _priority = 1 - - def __init__(self, operand, ref_period): - assert isinstance(operand, Expr) - assert isinstance(ref_period, float) - self.operand, self.ref_period = operand, ref_period - - def __eq__(lhs, rhs): - return rhs.__class__ == lhs.__class__ and \ - lhs.ref_period == rhs.ref_period and \ - lhs.operand == rhs.operand - - def free_vars(self): - return self.operand.free_vars() - -class MUToS(Conv): - def __str__(self): - return "mu->s({})".format(self.operand) - - def eval(self, env): - return self.operand.eval(env) * self.ref_period - - def fold(self, vars=None): - operand = self.operand.fold(vars) - if isinstance(operand, Const): - return Const(operand.value * self.ref_period) - else: - return MUToS(operand, ref_period=self.ref_period) - -class SToMU(Conv): - def __str__(self): - return "s->mu({})".format(self.operand) - - def eval(self, env): - return int(self.operand.eval(env) / self.ref_period) - - def fold(self, vars=None): - operand = self.operand.fold(vars) - if isinstance(operand, Const): - return Const(int(operand.value / self.ref_period)) - else: - return SToMU(operand, ref_period=self.ref_period) - -class BinOp(Expr): - def __init__(self, lhs, rhs): - self.lhs, self.rhs = lhs, rhs - - def __str__(self): - lhs = "({})".format(self.lhs) if self.lhs._priority > self._priority else str(self.lhs) - rhs = "({})".format(self.rhs) if self.rhs._priority > self._priority else str(self.rhs) - return "{} {} {}".format(lhs, self._symbol, rhs) - - def __eq__(lhs, rhs): - return rhs.__class__ == lhs.__class__ and lhs.lhs == rhs.lhs and lhs.rhs == rhs.rhs - - def eval(self, env): - return self.__class__._op(self.lhs.eval(env), self.rhs.eval(env)) - - def free_vars(self): - return self.lhs.free_vars() | self.rhs.free_vars() - - def _fold_binop(self, lhs, rhs): - if isinstance(lhs, Const) and lhs.__class__ == rhs.__class__: - return Const(self.__class__._op(lhs.value, rhs.value)) - elif isinstance(lhs, (MUToS, SToMU)) and lhs.__class__ == rhs.__class__: - return lhs.__class__(self.__class__(lhs.operand, rhs.operand), - ref_period=lhs.ref_period).fold() - else: - return self.__class__(lhs, rhs) - - def fold(self, vars=None): - return self._fold_binop(self.lhs.fold(vars), self.rhs.fold(vars)) - -class BinOpFixpoint(BinOp): - def _fold_binop(self, lhs, rhs): - if isinstance(lhs, Const) and lhs.value == self._fixpoint: - return rhs - elif isinstance(rhs, Const) and rhs.value == self._fixpoint: - return lhs - else: - return super()._fold_binop(lhs, rhs) - -class Add(BinOpFixpoint): - _priority = 2 - _symbol = "+" - _op = lambda a, b: a + b - _fixpoint = 0 - -class Mul(BinOpFixpoint): - _priority = 1 - _symbol = "*" - _op = lambda a, b: a * b - _fixpoint = 1 - -class Sub(BinOp): - _priority = 2 - _symbol = "-" - _op = lambda a, b: a - b - - def _fold_binop(self, lhs, rhs): - if isinstance(rhs, Const) and rhs.value == 0: - return lhs - else: - return super()._fold_binop(lhs, rhs) - -class Div(BinOp): - def _fold_binop(self, lhs, rhs): - if isinstance(rhs, Const) and rhs.value == 1: - return lhs - else: - return super()._fold_binop(lhs, rhs) - -class TrueDiv(Div): - _priority = 1 - _symbol = "/" - _op = lambda a, b: a / b if b != 0 else 0 - -class FloorDiv(Div): - _priority = 1 - _symbol = "//" - _op = lambda a, b: a // b if b != 0 else 0 - -class Max(Expr): - _priority = 1 - - def __init__(self, operands): - assert isinstance(operands, list) - assert all([isinstance(operand, Expr) for operand in operands]) - assert operands != [] - self.operands = operands - - def __str__(self): - return "max({})".format(", ".join([str(operand) for operand in self.operands])) - - def __eq__(lhs, rhs): - return rhs.__class__ == lhs.__class__ and lhs.operands == rhs.operands - - def free_vars(self): - return reduce(lambda a, b: a | b, [operand.free_vars() for operand in self.operands]) - - def eval(self, env): - return max([operand.eval() for operand in self.operands]) - - def fold(self, vars=None): - consts, exprs = [], [] - for operand in self.operands: - operand = operand.fold(vars) - if isinstance(operand, Const): - consts.append(operand.value) - elif operand not in exprs: - exprs.append(operand) - if len(consts) > 0: - exprs.append(Const(max(consts))) - if len(exprs) == 1: - return exprs[0] - else: - return Max(exprs) - -def is_const(expr, value=None): - expr = expr.fold() - if value is None: - return isinstance(expr, Const) - else: - return isinstance(expr, Const) and expr.value == value - -def is_zero(expr): - return is_const(expr, 0) diff --git a/artiq/compiler/ir.py b/artiq/compiler/ir.py deleted file mode 100644 index 3f984606f..000000000 --- a/artiq/compiler/ir.py +++ /dev/null @@ -1,1504 +0,0 @@ -""" -The :mod:`ir` module contains the intermediate representation -of the ARTIQ compiler. -""" - -from collections import OrderedDict -from pythonparser import ast -from . import types, builtins, iodelay - -# Generic SSA IR classes - -def escape_name(name): - if all([str.isalnum(x) or x == "." for x in name]): - return name - else: - return "\"{}\"".format(name.replace("\"", "\\\"")) - -class TBasicBlock(types.TMono): - def __init__(self): - super().__init__("label") - -def is_basic_block(typ): - return isinstance(typ, TBasicBlock) - -class TOption(types.TMono): - def __init__(self, value): - super().__init__("option", {"value": value}) - -def is_option(typ): - return isinstance(typ, TOption) - -class TKeyword(types.TMono): - def __init__(self, value): - super().__init__("keyword", {"value": value}) - -def is_keyword(typ): - return isinstance(typ, TKeyword) - - -# See rpc_proto.rs and comm_kernel.py:_{send,receive}_rpc_value. -def rpc_tag(typ, error_handler): - typ = typ.find() - if types.is_tuple(typ): - assert len(typ.elts) < 256 - return b"t" + bytes([len(typ.elts)]) + \ - b"".join([rpc_tag(elt_type, error_handler) - for elt_type in typ.elts]) - elif builtins.is_none(typ): - return b"n" - elif builtins.is_bool(typ): - return b"b" - elif builtins.is_int(typ, types.TValue(32)): - return b"i" - elif builtins.is_int(typ, types.TValue(64)): - return b"I" - elif builtins.is_float(typ): - return b"f" - elif builtins.is_str(typ): - return b"s" - elif builtins.is_bytes(typ): - return b"B" - elif builtins.is_bytearray(typ): - return b"A" - elif builtins.is_list(typ): - return b"l" + rpc_tag(builtins.get_iterable_elt(typ), error_handler) - elif builtins.is_array(typ): - num_dims = typ["num_dims"].value - return b"a" + bytes([num_dims]) + rpc_tag(typ["elt"], error_handler) - elif builtins.is_range(typ): - return b"r" + rpc_tag(builtins.get_iterable_elt(typ), error_handler) - elif is_keyword(typ): - return b"k" + rpc_tag(typ.params["value"], error_handler) - elif types.is_function(typ) or types.is_method(typ) or types.is_rpc(typ): - raise ValueError("RPC tag for functional value") - elif '__objectid__' in typ.attributes: - return b"O" - else: - error_handler(typ) - - -class Value: - """ - An SSA value that keeps track of its uses. - - :ivar type: (:class:`.types.Type`) type of this value - :ivar uses: (list of :class:`Value`) values that use this value - """ - - def __init__(self, typ): - self.uses, self.type = set(), typ.find() - - def replace_all_uses_with(self, value): - for user in set(self.uses): - user.replace_uses_of(self, value) - - def __str__(self): - return self.as_entity(type_printer=types.TypePrinter()) - -class Constant(Value): - """ - A constant value. - - :ivar value: (Python object) value - """ - - def __init__(self, value, typ): - super().__init__(typ) - self.value = value - - def as_operand(self, type_printer): - return self.as_entity(type_printer) - - def as_entity(self, type_printer): - return "{} {}".format(type_printer.name(self.type), - repr(self.value)) - - def __hash__(self): - return hash(self.value) - - def __eq__(self, other): - return isinstance(other, Constant) and \ - other.type == self.type and other.value == self.value - - def __ne__(self, other): - return not (self == other) - -class NamedValue(Value): - """ - An SSA value that has a name. - - :ivar name: (string) name of this value - :ivar function: (:class:`Function`) function containing this value - """ - - def __init__(self, typ, name): - super().__init__(typ) - self.name, self.function = name, None - - def set_name(self, new_name): - if self.function is not None: - self.function._remove_name(self.name) - self.name = self.function._add_name(new_name) - else: - self.name = new_name - - def _set_function(self, new_function): - if self.function != new_function: - if self.function is not None: - self.function._remove_name(self.name) - self.function = new_function - if self.function is not None: - self.name = self.function._add_name(self.name) - - def _detach(self): - self.function = None - - def as_operand(self, type_printer): - return "{} %{}".format(type_printer.name(self.type), - escape_name(self.name)) - -class User(NamedValue): - """ - An SSA value that has operands. - - :ivar operands: (list of :class:`Value`) operands of this value - """ - - def __init__(self, operands, typ, name): - super().__init__(typ, name) - self.operands = [] - self.set_operands(operands) - - def set_operands(self, new_operands): - for operand in set(self.operands): - operand.uses.remove(self) - self.operands = new_operands - for operand in set(self.operands): - operand.uses.add(self) - - def drop_references(self): - self.set_operands([]) - - def replace_uses_of(self, value, replacement): - assert value in self.operands - - for index, operand in enumerate(self.operands): - if operand == value: - self.operands[index] = replacement - - value.uses.remove(self) - replacement.uses.add(self) - -class Instruction(User): - """ - An SSA instruction. - - :ivar loc: (:class:`pythonparser.source.Range` or None) - source location - """ - - def __init__(self, operands, typ, name=""): - assert isinstance(operands, list) - assert isinstance(typ, types.Type) - super().__init__(operands, typ, name) - self.basic_block = None - self.loc = None - - def copy(self, mapper): - self_copy = self.__class__.__new__(self.__class__) - Instruction.__init__(self_copy, list(map(mapper, self.operands)), - self.type, self.name) - self_copy.loc = self.loc - return self_copy - - def set_basic_block(self, new_basic_block): - self.basic_block = new_basic_block - if self.basic_block is not None: - self._set_function(self.basic_block.function) - else: - self._set_function(None) - - def opcode(self): - """String representation of the opcode.""" - return "???" - - def _detach(self): - self.set_basic_block(None) - - def remove_from_parent(self): - if self.basic_block is not None: - self.basic_block.remove(self) - - def erase(self): - self.remove_from_parent() - self.drop_references() - # Check this after drop_references in case this - # is a self-referencing phi. - assert not any(self.uses) - - def replace_with(self, value): - self.replace_all_uses_with(value) - if isinstance(value, Instruction): - self.basic_block.replace(self, value) - self.drop_references() - else: - self.erase() - - def _operands_as_string(self, type_printer): - return ", ".join([operand.as_operand(type_printer) for operand in self.operands]) - - def as_entity(self, type_printer): - if builtins.is_none(self.type) and len(self.uses) == 0: - prefix = "" - else: - prefix = "%{} = {} ".format(escape_name(self.name), - type_printer.name(self.type)) - - if any(self.operands): - return "{}{} {}".format(prefix, self.opcode(), - self._operands_as_string(type_printer)) - else: - return "{}{}".format(prefix, self.opcode()) - -class Phi(Instruction): - """ - An SSA instruction that joins data flow. - - Use :meth:`incoming` and :meth:`add_incoming` instead of - directly reading :attr:`operands` or calling :meth:`set_operands`. - """ - - def __init__(self, typ, name=""): - super().__init__([], typ, name) - - def opcode(self): - return "phi" - - def incoming(self): - operand_iter = iter(self.operands) - while True: - try: - yield next(operand_iter), next(operand_iter) - except StopIteration: - return - - def incoming_blocks(self): - return (block for (value, block) in self.incoming()) - - def incoming_values(self): - return (value for (value, block) in self.incoming()) - - def incoming_value_for_block(self, target_block): - for (value, block) in self.incoming(): - if block == target_block: - return value - assert False - - def add_incoming(self, value, block): - assert value.type == self.type - self.operands.append(value) - value.uses.add(self) - self.operands.append(block) - block.uses.add(self) - - def remove_incoming_value(self, value): - index = self.operands.index(value) - assert index % 2 == 0 - self.operands[index].uses.remove(self) - self.operands[index + 1].uses.remove(self) - del self.operands[index:index + 2] - - def remove_incoming_block(self, block): - index = self.operands.index(block) - assert index % 2 == 1 - self.operands[index - 1].uses.remove(self) - self.operands[index].uses.remove(self) - del self.operands[index - 1:index + 1] - - def as_entity(self, type_printer): - if builtins.is_none(self.type): - prefix = "" - else: - prefix = "%{} = {} ".format(escape_name(self.name), - type_printer.name(self.type)) - - if any(self.operands): - operand_list = ["%{} => {}".format(escape_name(block.name), - value.as_operand(type_printer)) - for value, block in self.incoming()] - return "{}{} [{}]".format(prefix, self.opcode(), ", ".join(operand_list)) - else: - return "{}{} [???]".format(prefix, self.opcode()) - -class Terminator(Instruction): - """ - An SSA instruction that performs control flow. - """ - - def successors(self): - return [operand for operand in self.operands if isinstance(operand, BasicBlock)] - -class BasicBlock(NamedValue): - """ - A block of instructions with no control flow inside it. - - :ivar instructions: (list of :class:`Instruction`) - """ - _dump_loc = True - - def __init__(self, instructions, name=""): - super().__init__(TBasicBlock(), name) - self.instructions = [] - self.set_instructions(instructions) - - def set_instructions(self, new_insns): - for insn in self.instructions: - insn.detach() - self.instructions = new_insns - for insn in self.instructions: - insn.set_basic_block(self) - - def remove_from_parent(self): - if self.function is not None: - self.function.remove(self) - - def erase(self): - # self.instructions is updated while iterating - for insn in reversed(self.instructions): - insn.erase() - self.remove_from_parent() - # Check this after erasing instructions in case the block - # loops into itself. - assert not any(self.uses) - - def prepend(self, insn): - assert isinstance(insn, Instruction) - insn.set_basic_block(self) - self.instructions.insert(0, insn) - return insn - - def append(self, insn): - assert isinstance(insn, Instruction) - insn.set_basic_block(self) - self.instructions.append(insn) - return insn - - def index(self, insn): - return self.instructions.index(insn) - - def insert(self, insn, before): - assert isinstance(insn, Instruction) - insn.set_basic_block(self) - self.instructions.insert(self.index(before), insn) - return insn - - def remove(self, insn): - assert insn in self.instructions - insn._detach() - self.instructions.remove(insn) - return insn - - def replace(self, insn, replacement): - self.insert(replacement, before=insn) - self.remove(insn) - - def is_terminated(self): - return any(self.instructions) and isinstance(self.instructions[-1], Terminator) - - def terminator(self): - assert self.is_terminated() - return self.instructions[-1] - - def successors(self): - return self.terminator().successors() - - def predecessors(self): - return [use.basic_block for use in self.uses if isinstance(use, Terminator)] - - def as_entity(self, type_printer): - # Header - lines = ["{}:".format(escape_name(self.name))] - if self.function is not None: - lines[0] += " ; predecessors: {}".format( - ", ".join(sorted([escape_name(pred.name) for pred in self.predecessors()]))) - - # Annotated instructions - loc = None - for insn in self.instructions: - if self._dump_loc and loc != insn.loc: - loc = insn.loc - - if loc is None: - lines.append("; ") - else: - source_lines = loc.source_lines() - beg_col, end_col = loc.column(), loc.end().column() - source_lines[-1] = \ - source_lines[-1][:end_col] + "\x1b[0m" + source_lines[-1][end_col:] - source_lines[0] = \ - source_lines[0][:beg_col] + "\x1b[1;32m" + source_lines[0][beg_col:] - - line_desc = "{}:{}".format(loc.source_buffer.name, loc.line()) - lines += ["; {} {}".format(line_desc, line.rstrip("\n")) - for line in source_lines] - lines.append(" " + insn.as_entity(type_printer)) - - return "\n".join(lines) - - def __repr__(self): - return "".format(repr(self.name)) - -class Argument(NamedValue): - """ - A function argument. - - :ivar loc: (:class:`pythonparser.source.Range` or None) - source location - """ - def __init__(self, typ, name): - super().__init__(typ, name) - self.loc = None - - def as_entity(self, type_printer): - return self.as_operand(type_printer) - -class Function: - """ - A function containing SSA IR. - - :ivar loc: (:class:`pythonparser.source.Range` or None) - source location of function definition - :ivar is_internal: - (bool) if True, the function should not be accessible from outside - the module it is contained in - :ivar is_cold: - (bool) if True, the function should be considered rarely called - :ivar is_generated: - (bool) if True, the function will not appear in backtraces - :ivar flags: (set of str) Code generation flags. - Flag ``fast-math`` is the equivalent of gcc's ``-ffast-math``. - """ - - def __init__(self, typ, name, arguments, loc=None): - self.type, self.name, self.loc = typ, name, loc - self.names, self.arguments, self.basic_blocks = set(), [], [] - self.next_name = 1 - self.set_arguments(arguments) - self.is_internal = False - self.is_cold = False - self.is_generated = False - self.flags = {} - - def _remove_name(self, name): - self.names.remove(name) - - def _add_name(self, base_name): - if base_name == "": - name = "UNN.{}".format(self.next_name) - self.next_name += 1 - elif base_name in self.names: - name = "{}.{}".format(base_name, self.next_name) - self.next_name += 1 - else: - name = base_name - - self.names.add(name) - return name - - def set_arguments(self, new_arguments): - for argument in self.arguments: - argument._set_function(None) - self.arguments = new_arguments - for argument in self.arguments: - argument._set_function(self) - - def add(self, basic_block): - basic_block._set_function(self) - self.basic_blocks.append(basic_block) - - def remove(self, basic_block): - basic_block._detach() - self.basic_blocks.remove(basic_block) - - def entry(self): - assert any(self.basic_blocks) - return self.basic_blocks[0] - - def exits(self): - return [block for block in self.basic_blocks if not any(block.successors())] - - def instructions(self): - for basic_block in self.basic_blocks: - yield from iter(basic_block.instructions) - - def as_entity(self, type_printer): - postorder = [] - visited = set() - def visit(block): - visited.add(block) - for next_block in block.successors(): - if next_block not in visited: - visit(next_block) - postorder.append(block) - - visit(self.entry()) - - lines = [] - lines.append("{} {}({}) {{ ; type: {}".format( - type_printer.name(self.type.ret), self.name, - ", ".join([arg.as_operand(type_printer) for arg in self.arguments]), - type_printer.name(self.type))) - - postorder_blocks = list(reversed(postorder)) - orphan_blocks = [block for block in self.basic_blocks if block not in postorder] - for block in postorder_blocks + orphan_blocks: - lines.append(block.as_entity(type_printer)) - - lines.append("}") - return "\n".join(lines) - - def __str__(self): - return self.as_entity(types.TypePrinter()) - -# Python-specific SSA IR classes - -class TEnvironment(types.TMono): - def __init__(self, name, vars, outer=None): - assert isinstance(name, str) - self.env_name = name # for readable type names in LLVM IR - - if outer is not None: - assert isinstance(outer, TEnvironment) - env = OrderedDict({"$outer": outer}) - env.update(vars) - else: - env = OrderedDict(vars) - - super().__init__("environment", env) - - def type_of(self, name): - if name in self.params: - return self.params[name].find() - elif "$outer" in self.params: - return self.params["$outer"].type_of(name) - else: - assert False - - def outermost(self): - if "$outer" in self.params: - return self.params["$outer"].outermost() - else: - return self - - """ - Add a new binding, ensuring hygiene. - - :returns: (string) mangled name - """ - def add(self, base_name, typ): - name, counter = base_name, 1 - while name in self.params or name == "": - if base_name == "": - name = str(counter) - else: - name = "{}.{}".format(name, counter) - counter += 1 - - self.params[name] = typ.find() - return name - -def is_environment(typ): - return isinstance(typ, TEnvironment) - -class EnvironmentArgument(Argument): - """ - A function argument specifying an outer environment. - """ - - def as_operand(self, type_printer): - return "environment(...) %{}".format(escape_name(self.name)) - -class Alloc(Instruction): - """ - An instruction that allocates an object specified by - the type of the intsruction. - """ - - def __init__(self, operands, typ, name=""): - for operand in operands: assert isinstance(operand, Value) - super().__init__(operands, typ, name) - - def opcode(self): - return "alloc" - - def as_operand(self, type_printer): - if is_environment(self.type): - # Only show full environment in the instruction itself - return "%{}".format(escape_name(self.name)) - else: - return super().as_operand(type_printer) - -class GetLocal(Instruction): - """ - An intruction that loads a local variable from an environment, - possibly going through multiple levels of indirection. - - :ivar var_name: (string) variable name - """ - - """ - :param env: (:class:`Value`) local environment - :param var_name: (string) local variable name - """ - def __init__(self, env, var_name, name=""): - assert isinstance(env, Value) - assert isinstance(env.type, TEnvironment) - assert isinstance(var_name, str) - super().__init__([env], env.type.type_of(var_name), name) - self.var_name = var_name - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.var_name = self.var_name - return self_copy - - def opcode(self): - return "getlocal({})".format(repr(self.var_name)) - - def environment(self): - return self.operands[0] - -class SetLocal(Instruction): - """ - An intruction that stores a local variable into an environment, - possibly going through multiple levels of indirection. - - :ivar var_name: (string) variable name - """ - - """ - :param env: (:class:`Value`) local environment - :param var_name: (string) local variable name - :param value: (:class:`Value`) value to assign - """ - def __init__(self, env, var_name, value, name=""): - assert isinstance(env, Value) - assert isinstance(env.type, TEnvironment) - assert isinstance(var_name, str) - assert env.type.type_of(var_name) == value.type - assert isinstance(value, Value) - super().__init__([env, value], builtins.TNone(), name) - self.var_name = var_name - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.var_name = self.var_name - return self_copy - - def opcode(self): - return "setlocal({})".format(repr(self.var_name)) - - def environment(self): - return self.operands[0] - - def value(self): - return self.operands[1] - -class GetAttr(Instruction): - """ - An intruction that loads an attribute from an object, - or extracts a tuple element. - - :ivar attr: (string) variable name - """ - - """ - :param obj: (:class:`Value`) object or tuple - :param attr: (string or integer) attribute or index - """ - def __init__(self, obj, attr, name=""): - assert isinstance(obj, Value) - assert isinstance(attr, (str, int)) - if isinstance(attr, int): - assert isinstance(obj.type, types.TTuple) - typ = obj.type.elts[attr] - elif attr in obj.type.attributes: - typ = obj.type.attributes[attr] - else: - typ = obj.type.constructor.attributes[attr] - if types.is_function(typ) or types.is_rpc(typ): - typ = types.TMethod(obj.type, typ) - super().__init__([obj], typ, name) - self.attr = attr - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.attr = self.attr - return self_copy - - def opcode(self): - return "getattr({})".format(repr(self.attr)) - - def object(self): - return self.operands[0] - -class SetAttr(Instruction): - """ - An intruction that stores an attribute to an object. - - :ivar attr: (string) variable name - """ - - """ - :param obj: (:class:`Value`) object or tuple - :param attr: (string or integer) attribute - :param value: (:class:`Value`) value to store - """ - def __init__(self, obj, attr, value, name=""): - assert isinstance(obj, Value) - assert isinstance(attr, (str, int)) - assert isinstance(value, Value) - if isinstance(attr, int): - assert value.type == obj.type.elts[attr].find() - else: - assert value.type == obj.type.attributes[attr].find() - super().__init__([obj, value], builtins.TNone(), name) - self.attr = attr - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.attr = self.attr - return self_copy - - def opcode(self): - return "setattr({})".format(repr(self.attr)) - - def object(self): - return self.operands[0] - - def value(self): - return self.operands[1] - -class Offset(Instruction): - """ - An intruction that adds an offset to a pointer (indexes into a list). - - This is used to represent internally generated pointer arithmetic, and must - remain inside the same object (see :class:`GetElem` and LLVM's GetElementPtr). - """ - - """ - :param lst: (:class:`Value`) list - :param index: (:class:`Value`) index - """ - def __init__(self, base, offset, name=""): - assert isinstance(base, Value) - assert isinstance(offset, Value) - typ = types._TPointer(builtins.get_iterable_elt(base.type)) - super().__init__([base, offset], typ, name) - - def opcode(self): - return "offset" - - def base(self): - return self.operands[0] - - def index(self): - return self.operands[1] - -class GetElem(Instruction): - """ - An intruction that loads an element from a list. - """ - - """ - :param lst: (:class:`Value`) list - :param index: (:class:`Value`) index - """ - def __init__(self, lst, index, name=""): - assert isinstance(lst, Value) - assert isinstance(index, Value) - super().__init__([lst, index], builtins.get_iterable_elt(lst.type), name) - - def opcode(self): - return "getelem" - - def base(self): - return self.operands[0] - - def index(self): - return self.operands[1] - -class SetElem(Instruction): - """ - An intruction that stores an element into a list. - """ - - """ - :param lst: (:class:`Value`) list - :param index: (:class:`Value`) index - :param value: (:class:`Value`) value to store - """ - def __init__(self, lst, index, value, name=""): - assert isinstance(lst, Value) - assert isinstance(index, Value) - assert isinstance(value, Value) - assert builtins.get_iterable_elt(lst.type) == value.type.find() - super().__init__([lst, index, value], builtins.TNone(), name) - - def opcode(self): - return "setelem" - - def base(self): - return self.operands[0] - - def index(self): - return self.operands[1] - - def value(self): - return self.operands[2] - -class Coerce(Instruction): - """ - A coercion operation for numbers. - """ - - def __init__(self, value, typ, name=""): - assert isinstance(value, Value) - assert isinstance(typ, types.Type) - super().__init__([value], typ, name) - - def opcode(self): - return "coerce" - - def value(self): - return self.operands[0] - -class Arith(Instruction): - """ - An arithmetic operation on numbers. - - :ivar op: (:class:`pythonparser.ast.operator`) operation - """ - - """ - :param op: (:class:`pythonparser.ast.operator`) operation - :param lhs: (:class:`Value`) left-hand operand - :param rhs: (:class:`Value`) right-hand operand - """ - def __init__(self, op, lhs, rhs, name=""): - assert isinstance(op, ast.operator) - assert isinstance(lhs, Value) - assert isinstance(rhs, Value) - assert lhs.type == rhs.type - super().__init__([lhs, rhs], lhs.type, name) - self.op = op - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.op = self.op - return self_copy - - def opcode(self): - return "arith({})".format(type(self.op).__name__) - - def lhs(self): - return self.operands[0] - - def rhs(self): - return self.operands[1] - - -class Compare(Instruction): - """ - A comparison operation on numbers. - - :ivar op: (:class:`pythonparser.ast.cmpop`) operation - """ - - """ - :param op: (:class:`pythonparser.ast.cmpop`) operation - :param lhs: (:class:`Value`) left-hand operand - :param rhs: (:class:`Value`) right-hand operand - """ - def __init__(self, op, lhs, rhs, name=""): - assert isinstance(op, ast.cmpop) - assert isinstance(lhs, Value) - assert isinstance(rhs, Value) - assert lhs.type == rhs.type - super().__init__([lhs, rhs], builtins.TBool(), name) - self.op = op - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.op = self.op - return self_copy - - def opcode(self): - return "compare({})".format(type(self.op).__name__) - - def lhs(self): - return self.operands[0] - - def rhs(self): - return self.operands[1] - -class Builtin(Instruction): - """ - A builtin operation. Similar to a function call that - never raises. - - :ivar op: (string) operation name - """ - - """ - :param op: (string) operation name - """ - def __init__(self, op, operands, typ, name=None): - assert isinstance(op, str) - for operand in operands: assert isinstance(operand, Value) - if name is None: - name = "BLT.{}".format(op) - super().__init__(operands, typ, name) - self.op = op - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.op = self.op - return self_copy - - def opcode(self): - return "builtin({})".format(self.op) - -class Closure(Instruction): - """ - A closure creation operation. - - :ivar target_function: (:class:`Function`) function to invoke - """ - - """ - :param func: (:class:`Function`) function - :param env: (:class:`Value`) outer environment - """ - def __init__(self, func, env, name=""): - assert isinstance(func, Function) - assert isinstance(env, Value) - assert is_environment(env.type) - super().__init__([env], func.type, name) - self.target_function = func - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.target_function = self.target_function - return self_copy - - def opcode(self): - return "closure({})".format(self.target_function.name) - - def environment(self): - return self.operands[0] - -class Call(Instruction): - """ - A function call operation. - - :ivar arg_exprs: (dict of str to `iodelay.Expr`) - iodelay expressions for values of arguments - :ivar static_target_function: (:class:`Function` or None) - statically resolved callee - :ivar is_cold: (bool) - the callee function is cold - """ - - """ - :param func: (:class:`Value`) function to call - :param args: (list of :class:`Value`) function arguments - :param arg_exprs: (dict of str to `iodelay.Expr`) - """ - def __init__(self, func, args, arg_exprs, name=""): - assert isinstance(func, Value) - for arg in args: assert isinstance(arg, Value) - for arg in arg_exprs: - assert isinstance(arg, str) - assert isinstance(arg_exprs[arg], iodelay.Expr) - super().__init__([func] + args, func.type.ret, name) - self.arg_exprs = arg_exprs - self.static_target_function = None - self.is_cold = False - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.arg_exprs = self.arg_exprs - self_copy.static_target_function = self.static_target_function - return self_copy - - def opcode(self): - return "call" - - def target_function(self): - return self.operands[0] - - def arguments(self): - return self.operands[1:] - - def as_entity(self, type_printer): - result = super().as_entity(type_printer) - if self.static_target_function is not None: - result += " ; calls {}".format(self.static_target_function.name) - return result - -class Select(Instruction): - """ - A conditional select instruction. - """ - - """ - :param cond: (:class:`Value`) select condition - :param if_true: (:class:`Value`) value of select if condition is truthful - :param if_false: (:class:`Value`) value of select if condition is falseful - """ - def __init__(self, cond, if_true, if_false, name=""): - assert isinstance(cond, Value) - assert builtins.is_bool(cond.type) - assert isinstance(if_true, Value) - assert isinstance(if_false, Value) - assert if_true.type == if_false.type - super().__init__([cond, if_true, if_false], if_true.type, name) - - def opcode(self): - return "select" - - def condition(self): - return self.operands[0] - - def if_true(self): - return self.operands[1] - - def if_false(self): - return self.operands[2] - -class Quote(Instruction): - """ - A quote operation. Returns a host interpreter value as a constant. - - :ivar value: (string) operation name - """ - - """ - :param value: (string) operation name - """ - def __init__(self, value, typ, name=""): - super().__init__([], typ, name) - self.value = value - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.value = self.value - return self_copy - - def opcode(self): - return "quote({})".format(repr(self.value)) - -class Branch(Terminator): - """ - An unconditional branch instruction. - """ - - """ - :param target: (:class:`BasicBlock`) branch target - """ - def __init__(self, target, name=""): - assert isinstance(target, BasicBlock) - super().__init__([target], builtins.TNone(), name) - - def opcode(self): - return "branch" - - def target(self): - return self.operands[0] - - def set_target(self, new_target): - self.operands[0].uses.remove(self) - self.operands[0] = new_target - self.operands[0].uses.add(self) - -class BranchIf(Terminator): - """ - A conditional branch instruction. - """ - - """ - :param cond: (:class:`Value`) branch condition - :param if_true: (:class:`BasicBlock`) branch target if condition is truthful - :param if_false: (:class:`BasicBlock`) branch target if condition is falseful - """ - def __init__(self, cond, if_true, if_false, name=""): - assert isinstance(cond, Value) - assert builtins.is_bool(cond.type) - assert isinstance(if_true, BasicBlock) - assert isinstance(if_false, BasicBlock) - assert if_true != if_false # use Branch instead - super().__init__([cond, if_true, if_false], builtins.TNone(), name) - - def opcode(self): - return "branchif" - - def condition(self): - return self.operands[0] - - def if_true(self): - return self.operands[1] - - def if_false(self): - return self.operands[2] - -class IndirectBranch(Terminator): - """ - An indirect branch instruction. - """ - - """ - :param target: (:class:`Value`) branch target - :param destinations: (list of :class:`BasicBlock`) all possible values of `target` - """ - def __init__(self, target, destinations, name=""): - assert isinstance(target, Value) - assert all([isinstance(dest, BasicBlock) for dest in destinations]) - super().__init__([target] + destinations, builtins.TNone(), name) - - def opcode(self): - return "indirectbranch" - - def target(self): - return self.operands[0] - - def destinations(self): - return self.operands[1:] - - def add_destination(self, destination): - destination.uses.add(self) - self.operands.append(destination) - - def _operands_as_string(self, type_printer): - return "{}, [{}]".format(self.operands[0].as_operand(type_printer), - ", ".join([dest.as_operand(type_printer) - for dest in self.operands[1:]])) - -class Return(Terminator): - """ - A return instruction. - """ - - """ - :param value: (:class:`Value`) return value - """ - def __init__(self, value, name=""): - assert isinstance(value, Value) - super().__init__([value], builtins.TNone(), name) - - def opcode(self): - return "return" - - def value(self): - return self.operands[0] - -class Unreachable(Terminator): - """ - An instruction used to mark unreachable branches. - """ - - """ - :param target: (:class:`BasicBlock`) branch target - """ - def __init__(self, name=""): - super().__init__([], builtins.TNone(), name) - - def opcode(self): - return "unreachable" - -class Raise(Terminator): - """ - A raise instruction. - """ - - """ - :param value: (:class:`Value`) exception value - :param exn: (:class:`BasicBlock` or None) exceptional target - """ - def __init__(self, value=None, exn=None, name=""): - assert isinstance(value, Value) - operands = [value] - if exn is not None: - assert isinstance(exn, BasicBlock) - operands.append(exn) - super().__init__(operands, builtins.TNone(), name) - - def opcode(self): - return "raise" - - def value(self): - return self.operands[0] - - def exception_target(self): - if len(self.operands) > 1: - return self.operands[1] - -class Reraise(Terminator): - """ - A reraise instruction. - """ - - """ - :param exn: (:class:`BasicBlock` or None) exceptional target - """ - def __init__(self, exn=None, name=""): - operands = [] - if exn is not None: - assert isinstance(exn, BasicBlock) - operands.append(exn) - super().__init__(operands, builtins.TNone(), name) - - def opcode(self): - return "reraise" - - def exception_target(self): - if len(self.operands) > 0: - return self.operands[0] - -class Invoke(Terminator): - """ - A function call operation that supports exception handling. - - :ivar arg_exprs: (dict of str to `iodelay.Expr`) - iodelay expressions for values of arguments - :ivar static_target_function: (:class:`Function` or None) - statically resolved callee - :ivar is_cold: (bool) - the callee function is cold - """ - - """ - :param func: (:class:`Value`) function to call - :param args: (list of :class:`Value`) function arguments - :param normal: (:class:`BasicBlock`) normal target - :param exn: (:class:`BasicBlock`) exceptional target - :param arg_exprs: (dict of str to `iodelay.Expr`) - """ - def __init__(self, func, args, arg_exprs, normal, exn, name=""): - assert isinstance(func, Value) - for arg in args: assert isinstance(arg, Value) - assert isinstance(normal, BasicBlock) - assert isinstance(exn, BasicBlock) - for arg in arg_exprs: - assert isinstance(arg, str) - assert isinstance(arg_exprs[arg], iodelay.Expr) - super().__init__([func] + args + [normal, exn], func.type.ret, name) - self.arg_exprs = arg_exprs - self.static_target_function = None - self.is_cold = False - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.arg_exprs = self.arg_exprs - self_copy.static_target_function = self.static_target_function - return self_copy - - def opcode(self): - return "invoke" - - def target_function(self): - return self.operands[0] - - def arguments(self): - return self.operands[1:-2] - - def normal_target(self): - return self.operands[-2] - - def exception_target(self): - return self.operands[-1] - - def _operands_as_string(self, type_printer): - result = ", ".join([operand.as_operand(type_printer) for operand in self.operands[:-2]]) - result += " to {} unwind {}".format(self.operands[-2].as_operand(type_printer), - self.operands[-1].as_operand(type_printer)) - return result - - def as_entity(self, type_printer): - result = super().as_entity(type_printer) - if self.static_target_function is not None: - result += " ; calls {}".format(self.static_target_function.name) - return result - -class LandingPad(Terminator): - """ - An instruction that gives an incoming exception a name and - dispatches it according to its type. - - Once dispatched, the exception should be cast to its proper - type by calling the "exncast" builtin on the landing pad value. - - :ivar types: (a list of :class:`builtins.TException`) - exception types corresponding to the basic block operands - """ - - def __init__(self, cleanup, name=""): - super().__init__([cleanup], builtins.TException(), name) - self.types = [] - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.types = list(self.types) - return self_copy - - def opcode(self): - return "landingpad" - - def cleanup(self): - return self.operands[0] - - def clauses(self): - return zip(self.operands[1:], self.types) - - def add_clause(self, target, typ): - assert isinstance(target, BasicBlock) - assert typ is None or builtins.is_exception(typ) - self.operands.append(target) - self.types.append(typ.find() if typ is not None else None) - target.uses.add(self) - - def _operands_as_string(self, type_printer): - table = [] - for target, typ in self.clauses(): - if typ is None: - table.append("... => {}".format(target.as_operand(type_printer))) - else: - table.append("{} => {}".format(type_printer.name(typ), - target.as_operand(type_printer))) - return "cleanup {}, [{}]".format(self.cleanup().as_operand(type_printer), - ", ".join(table)) - -class Delay(Terminator): - """ - A delay operation. Ties an :class:`iodelay.Expr` to SSA values so that - inlining could lead to the expression folding to a constant. - - :ivar interval: (:class:`iodelay.Expr`) expression - """ - - """ - :param interval: (:class:`iodelay.Expr`) expression - :param call: (:class:`Call` or ``Constant(None, builtins.TNone())``) - the call instruction that caused this delay, if any - :param target: (:class:`BasicBlock`) branch target - """ - def __init__(self, interval, decomposition, target, name=""): - assert isinstance(decomposition, Call) or isinstance(decomposition, Invoke) or \ - isinstance(decomposition, Builtin) and decomposition.op in ("delay", "delay_mu") - assert isinstance(target, BasicBlock) - super().__init__([decomposition, target], builtins.TNone(), name) - self.interval = interval - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.interval = self.interval - return self_copy - - def decomposition(self): - return self.operands[0] - - def set_decomposition(self, new_decomposition): - self.operands[0].uses.remove(self) - self.operands[0] = new_decomposition - self.operands[0].uses.add(self) - - def target(self): - return self.operands[1] - - def set_target(self, new_target): - self.operands[1].uses.remove(self) - self.operands[1] = new_target - self.operands[1].uses.add(self) - - def _operands_as_string(self, type_printer): - result = "decomp {}, to {}".format(self.decomposition().as_operand(type_printer), - self.target().as_operand(type_printer)) - return result - - def opcode(self): - return "delay({})".format(self.interval) - -class Loop(Terminator): - """ - A terminator for loop headers that carries metadata useful - for unrolling. It includes an :class:`iodelay.Expr` specifying - the trip count, tied to SSA values so that inlining could lead - to the expression folding to a constant. - - :ivar trip_count: (:class:`iodelay.Expr`) - expression for trip count - """ - - """ - :param trip_count: (:class:`iodelay.Expr`) expression - :param indvar: (:class:`Phi`) - phi node corresponding to the induction SSA value, - which advances from ``0`` to ``trip_count - 1`` - :param cond: (:class:`Value`) branch condition - :param if_true: (:class:`BasicBlock`) branch target if condition is truthful - :param if_false: (:class:`BasicBlock`) branch target if condition is falseful - """ - def __init__(self, trip_count, indvar, cond, if_true, if_false, name=""): - assert isinstance(indvar, Phi) - assert isinstance(cond, Value) - assert builtins.is_bool(cond.type) - assert isinstance(if_true, BasicBlock) - assert isinstance(if_false, BasicBlock) - super().__init__([indvar, cond, if_true, if_false], builtins.TNone(), name) - self.trip_count = trip_count - - def copy(self, mapper): - self_copy = super().copy(mapper) - self_copy.trip_count = self.trip_count - return self_copy - - def induction_variable(self): - return self.operands[0] - - def condition(self): - return self.operands[1] - - def if_true(self): - return self.operands[2] - - def if_false(self): - return self.operands[3] - - def _operands_as_string(self, type_printer): - result = "indvar {}, if {}, {}, {}".format( - *list(map(lambda value: value.as_operand(type_printer), self.operands))) - return result - - def opcode(self): - return "loop({} times)".format(self.trip_count) - -class Interleave(Terminator): - """ - An instruction that schedules several threads of execution - in parallel. - """ - - def __init__(self, destinations, name=""): - super().__init__(destinations, builtins.TNone(), name) - - def opcode(self): - return "interleave" - - def destinations(self): - return self.operands - - def add_destination(self, destination): - destination.uses.add(self) - self.operands.append(destination) diff --git a/artiq/compiler/kernel.ld b/artiq/compiler/kernel.ld deleted file mode 100644 index 6523d631a..000000000 --- a/artiq/compiler/kernel.ld +++ /dev/null @@ -1,53 +0,0 @@ -/* Force ld to make the ELF header as loadable. */ -PHDRS -{ - headers PT_LOAD FILEHDR PHDRS ; - text PT_LOAD ; - data PT_LOAD ; - dynamic PT_DYNAMIC ; - eh_frame PT_GNU_EH_FRAME ; -} - -SECTIONS -{ - /* Push back .text section enough so that ld.lld not complain */ - . = SIZEOF_HEADERS; - - .text : - { - *(.text .text.*) - } : text - - .rodata : - { - *(.rodata .rodata.*) - } - - .eh_frame : - { - KEEP(*(.eh_frame)) - } : text - - .eh_frame_hdr : - { - KEEP(*(.eh_frame_hdr)) - } : text : eh_frame - - .data : - { - *(.data) - } : data - - .dynamic : - { - *(.dynamic) - } : data : dynamic - - .bss (NOLOAD) : ALIGN(4) - { - __bss_start = .; - *(.sbss .sbss.* .bss .bss.*); - . = ALIGN(4); - _end = .; - } -} diff --git a/artiq/compiler/math_fns.py b/artiq/compiler/math_fns.py deleted file mode 100644 index 35d23b534..000000000 --- a/artiq/compiler/math_fns.py +++ /dev/null @@ -1,132 +0,0 @@ -r""" -The :mod:`math_fns` module lists math-related functions from NumPy recognized -by the ARTIQ compiler so host function objects can be :func:`match`\ ed to -the compiler type metadata describing their core device analogue. -""" - -from collections import OrderedDict -import numpy -from . import builtins, types - -# Some special mathematical functions are exposed via their scipy.special -# equivalents. Since the rest of the ARTIQ core does not depend on SciPy, -# gracefully handle it not being present, making the functions simply not -# available. -try: - import scipy.special as scipy_special -except ImportError: - scipy_special = None - -#: float -> float numpy.* math functions for which llvm.* intrinsics exist. -unary_fp_intrinsics = [(name, "llvm." + name + ".f64") for name in [ - "sin", - "cos", - "exp", - "exp2", - "log", - "log10", - "log2", - "fabs", - "floor", - "ceil", - "trunc", - "sqrt", -]] + [ - # numpy.rint() seems to (NumPy 1.19.0, Python 3.8.5, Linux x86_64) - # implement round-to-even, but unfortunately, rust-lang/libm only - # provides round(), which always rounds away from zero. - # - # As there is no equivalent of the latter in NumPy (nor any other - # basic rounding function), expose round() as numpy.rint anyway, - # even if the rounding modes don't match up, so there is some way - # to do rounding on the core device. (numpy.round() has entirely - # different semantics; it rounds to a configurable number of - # decimals.) - ("rint", "llvm.round.f64"), -] - -#: float -> float numpy.* math functions lowered to runtime calls. -unary_fp_runtime_calls = [ - ("tan", "tan"), - ("arcsin", "asin"), - ("arccos", "acos"), - ("arctan", "atan"), - ("sinh", "sinh"), - ("cosh", "cosh"), - ("tanh", "tanh"), - ("arcsinh", "asinh"), - ("arccosh", "acosh"), - ("arctanh", "atanh"), - ("expm1", "expm1"), - ("cbrt", "cbrt"), -] - -#: float -> float numpy.* math functions lowered to runtime calls. -unary_fp_runtime_calls = [ - ("tan", "tan"), - ("arcsin", "asin"), - ("arccos", "acos"), - ("arctan", "atan"), - ("sinh", "sinh"), - ("cosh", "cosh"), - ("tanh", "tanh"), - ("arcsinh", "asinh"), - ("arccosh", "acosh"), - ("arctanh", "atanh"), - ("expm1", "expm1"), - ("cbrt", "cbrt"), -] - -scipy_special_unary_runtime_calls = [ - ("erf", "erf"), - ("erfc", "erfc"), - ("gamma", "tgamma"), - ("gammaln", "lgamma"), - ("j0", "j0"), - ("j1", "j1"), - ("y0", "y0"), - ("y1", "y1"), -] -# Not mapped: jv/yv, libm only supports integer orders. - -#: (float, float) -> float numpy.* math functions lowered to runtime calls. -binary_fp_runtime_calls = [ - ("arctan2", "atan2"), - ("copysign", "copysign"), - ("fmax", "fmax"), - ("fmin", "fmin"), - # ("ldexp", "ldexp"), # One argument is an int; would need a bit more plumbing. - ("hypot", "hypot"), - ("nextafter", "nextafter"), -] - -#: Array handling builtins (special treatment due to allocations). -numpy_builtins = ["transpose"] - - -def fp_runtime_type(name, arity): - args = [("arg{}".format(i), builtins.TFloat()) for i in range(arity)] - return types.TExternalFunction( - OrderedDict(args), - builtins.TFloat(), - name, - # errno isn't observable from ARTIQ Python. - flags={"nounwind", "nowrite"}, - broadcast_across_arrays=True) - - -math_fn_map = { - getattr(numpy, symbol): fp_runtime_type(mangle, arity=1) - for symbol, mangle in (unary_fp_intrinsics + unary_fp_runtime_calls) -} -for symbol, mangle in binary_fp_runtime_calls: - math_fn_map[getattr(numpy, symbol)] = fp_runtime_type(mangle, arity=2) -for name in numpy_builtins: - math_fn_map[getattr(numpy, name)] = types.TBuiltinFunction("numpy." + name) -if scipy_special is not None: - for symbol, mangle in scipy_special_unary_runtime_calls: - math_fn_map[getattr(scipy_special, symbol)] = fp_runtime_type(mangle, arity=1) - - -def match(obj): - return math_fn_map.get(obj, None) diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py deleted file mode 100644 index d43404b20..000000000 --- a/artiq/compiler/module.py +++ /dev/null @@ -1,98 +0,0 @@ -""" -The :class:`Module` class encapsulates a single Python module, -which corresponds to a single ARTIQ translation unit (one LLVM -bitcode file and one object file, unless LTO is used). -A :class:`Module` can be created from a typed AST. - -The :class:`Source` class parses a single source file or -string and infers types for it using a trivial :module:`prelude`. -""" - -import os -from pythonparser import source, diagnostic, parse_buffer -from . import prelude, types, transforms, analyses, validators - -class Source: - def __init__(self, source_buffer, engine=None): - if engine is None: - self.engine = diagnostic.Engine(all_errors_are_fatal=True) - else: - self.engine = engine - self.embedding_map = None - self.name, _ = os.path.splitext(os.path.basename(source_buffer.name)) - - asttyped_rewriter = transforms.ASTTypedRewriter(engine=engine, - prelude=prelude.globals()) - inferencer = transforms.Inferencer(engine=engine) - - self.parsetree, self.comments = parse_buffer(source_buffer, engine=engine) - self.typedtree = asttyped_rewriter.visit(self.parsetree) - self.globals = asttyped_rewriter.globals - inferencer.visit(self.typedtree) - - @classmethod - def from_string(cls, source_string, name="input.py", first_line=1, engine=None): - return cls(source.Buffer(source_string + "\n", name, first_line), engine=engine) - - @classmethod - def from_filename(cls, filename, engine=None): - with open(filename) as f: - return cls(source.Buffer(f.read(), filename, 1), engine=engine) - -class Module: - def __init__(self, src, ref_period=1e-6, attribute_writeback=True, remarks=False): - self.attribute_writeback = attribute_writeback - self.engine = src.engine - self.embedding_map = src.embedding_map - self.name = src.name - self.globals = src.globals - - int_monomorphizer = transforms.IntMonomorphizer(engine=self.engine) - cast_monomorphizer = transforms.CastMonomorphizer(engine=self.engine) - inferencer = transforms.Inferencer(engine=self.engine) - monomorphism_validator = validators.MonomorphismValidator(engine=self.engine) - escape_validator = validators.EscapeValidator(engine=self.engine) - iodelay_estimator = transforms.IODelayEstimator(engine=self.engine, - ref_period=ref_period) - constness_validator = validators.ConstnessValidator(engine=self.engine) - artiq_ir_generator = transforms.ARTIQIRGenerator(engine=self.engine, - module_name=src.name, - ref_period=ref_period) - dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine) - local_access_validator = validators.LocalAccessValidator(engine=self.engine) - local_demoter = transforms.LocalDemoter() - constant_hoister = transforms.ConstantHoister() - devirtualization = analyses.Devirtualization() - interleaver = transforms.Interleaver(engine=self.engine) - invariant_detection = analyses.InvariantDetection(engine=self.engine) - - int_monomorphizer.visit(src.typedtree) - cast_monomorphizer.visit(src.typedtree) - inferencer.visit(src.typedtree) - monomorphism_validator.visit(src.typedtree) - escape_validator.visit(src.typedtree) - iodelay_estimator.visit_fixpoint(src.typedtree) - constness_validator.visit(src.typedtree) - devirtualization.visit(src.typedtree) - self.artiq_ir = artiq_ir_generator.visit(src.typedtree) - artiq_ir_generator.annotate_calls(devirtualization) - dead_code_eliminator.process(self.artiq_ir) - interleaver.process(self.artiq_ir) - local_access_validator.process(self.artiq_ir) - local_demoter.process(self.artiq_ir) - constant_hoister.process(self.artiq_ir) - if remarks: - invariant_detection.process(self.artiq_ir) - - def build_llvm_ir(self, target): - """Compile the module to LLVM IR for the specified target.""" - llvm_ir_generator = transforms.LLVMIRGenerator( - engine=self.engine, module_name=self.name, target=target, - embedding_map=self.embedding_map) - return llvm_ir_generator.process(self.artiq_ir, - attribute_writeback=self.attribute_writeback) - - def __repr__(self): - printer = types.TypePrinter() - globals = ["%s: %s" % (var, printer.name(self.globals[var])) for var in self.globals] - return "" % (repr(self.name), ",\n ".join(globals)) diff --git a/artiq/compiler/prelude.py b/artiq/compiler/prelude.py deleted file mode 100644 index 13f319650..000000000 --- a/artiq/compiler/prelude.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -The :mod:`prelude` module contains the initial global environment -in which ARTIQ kernels are evaluated. -""" - -from . import builtins - -def globals(): - return { - # Value constructors - "bool": builtins.fn_bool(), - "int": builtins.fn_int(), - "float": builtins.fn_float(), - "str": builtins.fn_str(), - "bytes": builtins.fn_bytes(), - "bytearray": builtins.fn_bytearray(), - "list": builtins.fn_list(), - "array": builtins.fn_array(), - "range": builtins.fn_range(), - "int32": builtins.fn_int32(), - "int64": builtins.fn_int64(), - - # Exception constructors - "Exception": builtins.fn_Exception(), - "IndexError": builtins.fn_IndexError(), - "ValueError": builtins.fn_ValueError(), - "ZeroDivisionError": builtins.fn_ZeroDivisionError(), - "RuntimeError": builtins.fn_RuntimeError(), - - # Built-in Python functions - "len": builtins.fn_len(), - "round": builtins.fn_round(), - "abs": builtins.fn_abs(), - "min": builtins.fn_min(), - "max": builtins.fn_max(), - "print": builtins.fn_print(), - - # ARTIQ decorators - "kernel": builtins.fn_kernel(), - "portable": builtins.fn_kernel(), - "rpc": builtins.fn_kernel(), - - # ARTIQ context managers - "parallel": builtins.obj_parallel(), - "interleave": builtins.obj_interleave(), - "sequential": builtins.obj_sequential(), - - # ARTIQ time management functions - "delay": builtins.fn_delay(), - "now_mu": builtins.fn_now_mu(), - "delay_mu": builtins.fn_delay_mu(), - "at_mu": builtins.fn_at_mu(), - - # ARTIQ utility functions - "rtio_log": builtins.fn_rtio_log(), - "core_log": builtins.fn_print(), - } diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py deleted file mode 100644 index e908ce38a..000000000 --- a/artiq/compiler/targets.py +++ /dev/null @@ -1,277 +0,0 @@ -import os, sys, tempfile, subprocess, io -from artiq.compiler import types, ir -from llvmlite import ir as ll, binding as llvm - -llvm.initialize() -llvm.initialize_all_targets() -llvm.initialize_all_asmprinters() - -class RunTool: - def __init__(self, pattern, **tempdata): - self._pattern = pattern - self._tempdata = tempdata - self._tempnames = {} - self._tempfiles = {} - - def __enter__(self): - for key, data in self._tempdata.items(): - if data is None: - fd, filename = tempfile.mkstemp() - os.close(fd) - self._tempnames[key] = filename - else: - with tempfile.NamedTemporaryFile(delete=False) as f: - f.write(data) - self._tempnames[key] = f.name - - cmdline = [] - for argument in self._pattern: - cmdline.append(argument.format(**self._tempnames)) - - # https://bugs.python.org/issue17023 - windows = os.name == "nt" - process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - universal_newlines=True, shell=windows) - stdout, stderr = process.communicate() - if process.returncode != 0: - raise Exception("{} invocation failed: {}". - format(cmdline[0], stderr)) - - self._tempfiles["__stdout__"] = io.StringIO(stdout) - for key in self._tempdata: - if self._tempdata[key] is None: - self._tempfiles[key] = open(self._tempnames[key], "rb") - return self._tempfiles - - def __exit__(self, exc_typ, exc_value, exc_trace): - for file in self._tempfiles.values(): - file.close() - for filename in self._tempnames.values(): - os.unlink(filename) - -def _dump(target, kind, suffix, content): - if target is not None: - print("====== {} DUMP ======".format(kind.upper()), file=sys.stderr) - content_value = content() - if isinstance(content_value, str): - content_value = bytes(content_value, 'utf-8') - if target == "": - file = tempfile.NamedTemporaryFile(suffix=suffix, delete=False) - else: - file = open(target + suffix, "wb") - file.write(content_value) - file.close() - print("{} dumped as {}".format(kind, file.name), file=sys.stderr) - -class Target: - """ - A description of the target environment where the binaries - generated by the ARTIQ compiler will be deployed. - - :var triple: (string) - LLVM target triple, e.g. ``"riscv32"`` - :var data_layout: (string) - LLVM target data layout, e.g. ``"E-m:e-p:32:32-i64:32-f64:32-v64:32-v128:32-a:0:32-n32"`` - :var features: (list of string) - LLVM target CPU features, e.g. ``["mul", "div", "ffl1"]`` - :var print_function: (string) - Name of a formatted print functions (with the signature of ``printf``) - provided by the target, e.g. ``"printf"``. - :var now_pinning: (boolean) - Whether the target implements the now-pinning RTIO optimization. - """ - triple = "unknown" - data_layout = "" - features = [] - print_function = "printf" - now_pinning = True - - tool_ld = "ld.lld" - tool_strip = "llvm-strip" - tool_addr2line = "llvm-addr2line" - tool_cxxfilt = "llvm-cxxfilt" - - def __init__(self): - self.llcontext = ll.Context() - - def target_machine(self): - lltarget = llvm.Target.from_triple(self.triple) - llmachine = lltarget.create_target_machine( - features=",".join(["+{}".format(f) for f in self.features]), - reloc="pic", codemodel="default") - llmachine.set_asm_verbosity(True) - return llmachine - - def optimize(self, llmodule): - llpassmgr = llvm.create_module_pass_manager() - - # Register our alias analysis passes. - llpassmgr.add_basic_alias_analysis_pass() - llpassmgr.add_type_based_alias_analysis_pass() - - # Start by cleaning up after our codegen and exposing as much - # information to LLVM as possible. - llpassmgr.add_constant_merge_pass() - llpassmgr.add_cfg_simplification_pass() - llpassmgr.add_instruction_combining_pass() - llpassmgr.add_sroa_pass() - llpassmgr.add_dead_code_elimination_pass() - llpassmgr.add_function_attrs_pass() - llpassmgr.add_global_optimizer_pass() - - # Now, actually optimize the code. - llpassmgr.add_function_inlining_pass(275) - llpassmgr.add_ipsccp_pass() - llpassmgr.add_instruction_combining_pass() - llpassmgr.add_gvn_pass() - llpassmgr.add_cfg_simplification_pass() - llpassmgr.add_licm_pass() - - # Clean up after optimizing. - llpassmgr.add_dead_arg_elimination_pass() - llpassmgr.add_global_dce_pass() - - llpassmgr.run(llmodule) - - def compile(self, module): - """Compile the module to a relocatable object for this target.""" - - if os.getenv("ARTIQ_DUMP_SIG"): - print("====== MODULE_SIGNATURE DUMP ======", file=sys.stderr) - print(module, file=sys.stderr) - - if os.getenv("ARTIQ_IR_NO_LOC") is not None: - ir.BasicBlock._dump_loc = False - - type_printer = types.TypePrinter() - _dump(os.getenv("ARTIQ_DUMP_IR"), "ARTIQ IR", ".txt", - lambda: "\n".join(fn.as_entity(type_printer) for fn in module.artiq_ir)) - - llmod = module.build_llvm_ir(self) - - try: - llparsedmod = llvm.parse_assembly(str(llmod)) - llparsedmod.verify() - except RuntimeError: - _dump("", "LLVM IR (broken)", ".ll", lambda: str(llmod)) - raise - - _dump(os.getenv("ARTIQ_DUMP_UNOPT_LLVM"), "LLVM IR (generated)", "_unopt.ll", - lambda: str(llparsedmod)) - - self.optimize(llparsedmod) - - _dump(os.getenv("ARTIQ_DUMP_LLVM"), "LLVM IR (optimized)", ".ll", - lambda: str(llparsedmod)) - - return llparsedmod - - def assemble(self, llmodule): - llmachine = self.target_machine() - - _dump(os.getenv("ARTIQ_DUMP_ASM"), "Assembly", ".s", - lambda: llmachine.emit_assembly(llmodule)) - - _dump(os.getenv("ARTIQ_DUMP_OBJ"), "Object file", ".o", - lambda: llmachine.emit_object(llmodule)) - - return llmachine.emit_object(llmodule) - - def link(self, objects): - """Link the relocatable objects into a shared library for this target.""" - with RunTool([self.tool_ld, "-shared", "--eh-frame-hdr"] + - ["-T" + os.path.join(os.path.dirname(__file__), "kernel.ld")] + - ["{{obj{}}}".format(index) for index in range(len(objects))] + - ["-x"] + - ["-o", "{output}"], - output=None, - **{"obj{}".format(index): obj for index, obj in enumerate(objects)}) \ - as results: - library = results["output"].read() - - _dump(os.getenv("ARTIQ_DUMP_ELF"), "Shared library", ".elf", - lambda: library) - - return library - - def compile_and_link(self, modules): - return self.link([self.assemble(self.compile(module)) for module in modules]) - - def strip(self, library): - with RunTool([self.tool_strip, "--strip-debug", "{library}", "-o", "{output}"], - library=library, output=None) \ - as results: - return results["output"].read() - - def symbolize(self, library, addresses): - if addresses == []: - return [] - - # We got a list of return addresses, i.e. addresses of instructions - # just after the call. Offset them back to get an address somewhere - # inside the call instruction (or its delay slot), since that's what - # the backtrace entry should point at. - offset_addresses = [hex(addr - 1) for addr in addresses] - with RunTool([self.tool_addr2line, "--addresses", "--functions", "--inlines", - "--demangle", "--exe={library}"] + offset_addresses, - library=library) \ - as results: - lines = iter(results["__stdout__"].read().rstrip().split("\n")) - backtrace = [] - while True: - try: - address_or_function = next(lines) - except StopIteration: - break - if address_or_function[:2] == "0x": - address = int(address_or_function[2:], 16) + 1 # remove offset - function = next(lines) - else: - address = backtrace[-1][4] # inlined - function = address_or_function - location = next(lines) - - filename, line = location.rsplit(":", 1) - if filename == "??" or filename == "": - continue - if line == "?": - line = -1 - else: - line = int(line) - # can't get column out of addr2line D: - backtrace.append((filename, line, -1, function, address)) - return backtrace - - def demangle(self, names): - with RunTool([self.tool_cxxfilt] + names) as results: - return results["__stdout__"].read().rstrip().split("\n") - -class NativeTarget(Target): - def __init__(self): - super().__init__() - self.triple = llvm.get_default_triple() - host_data_layout = str(llvm.targets.Target.from_default_triple().create_target_machine().target_data) - -class RISCVTarget(Target): - triple = "riscv32-unknown-linux" - data_layout = "e-m:e-p:32:32-i64:64-n32-S128" - features = ["m", "a"] - print_function = "core_log" - now_pinning = True - - tool_ld = "ld.lld" - tool_strip = "llvm-strip" - tool_addr2line = "llvm-addr2line" - tool_cxxfilt = "llvm-cxxfilt" - -class CortexA9Target(Target): - triple = "armv7-unknown-linux-gnueabihf" - data_layout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" - features = ["dsp", "fp16", "neon", "vfp3"] - print_function = "core_log" - now_pinning = False - - tool_ld = "ld.lld" - tool_strip = "llvm-strip" - tool_addr2line = "llvm-addr2line" - tool_cxxfilt = "llvm-cxxfilt" diff --git a/artiq/compiler/testbench/__init__.py b/artiq/compiler/testbench/__init__.py deleted file mode 100644 index 68ea51d7b..000000000 --- a/artiq/compiler/testbench/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -import time, cProfile as profile, pstats - -def benchmark(f, name): - profiler = profile.Profile() - profiler.enable() - - start = time.perf_counter() - end = 0 - runs = 0 - while end - start < 5 or runs < 10: - f() - runs += 1 - end = time.perf_counter() - - profiler.create_stats() - - print("{} {} runs: {:.2f}s, {:.2f}ms/run".format( - runs, name, end - start, (end - start) / runs * 1000)) - - stats = pstats.Stats(profiler) - stats.strip_dirs().sort_stats('time').print_stats(10) diff --git a/artiq/compiler/testbench/embedding.py b/artiq/compiler/testbench/embedding.py deleted file mode 100644 index c637c4b3a..000000000 --- a/artiq/compiler/testbench/embedding.py +++ /dev/null @@ -1,46 +0,0 @@ -import sys, os, tokenize - -from artiq.master.databases import DeviceDB -from artiq.master.worker_db import DeviceManager - -import artiq.coredevice.core -from artiq.coredevice.core import Core, CompileError - -def _render_diagnostic(diagnostic, colored): - return "\n".join(diagnostic.render(only_line=True)) - -artiq.coredevice.core._render_diagnostic = _render_diagnostic - -def main(): - if len(sys.argv) > 1 and sys.argv[1] == "+diag": - del sys.argv[1] - diag = True - else: - diag = False - - if len(sys.argv) > 1 and sys.argv[1] == "+compile": - del sys.argv[1] - compile_only = True - else: - compile_only = False - - ddb_path = os.path.join(os.path.dirname(sys.argv[1]), "device_db.py") - dmgr = DeviceManager(DeviceDB(ddb_path)) - - with tokenize.open(sys.argv[1]) as f: - testcase_code = compile(f.read(), f.name, "exec") - testcase_vars = {'__name__': 'testbench', 'dmgr': dmgr} - exec(testcase_code, testcase_vars) - - try: - core = dmgr.get("core") - if compile_only: - core.compile(testcase_vars["entrypoint"], (), {}) - else: - core.run(testcase_vars["entrypoint"], (), {}) - except CompileError as error: - if not diag: - exit(1) - -if __name__ == "__main__": - main() diff --git a/artiq/compiler/testbench/inferencer.py b/artiq/compiler/testbench/inferencer.py deleted file mode 100644 index 659b3b052..000000000 --- a/artiq/compiler/testbench/inferencer.py +++ /dev/null @@ -1,103 +0,0 @@ -import sys, fileinput, os -from pythonparser import source, diagnostic, algorithm, parse_buffer -from .. import prelude, types -from ..transforms import ASTTypedRewriter, Inferencer, IntMonomorphizer, CastMonomorphizer -from ..transforms import IODelayEstimator -from ..validators import ConstnessValidator - -class Printer(algorithm.Visitor): - """ - :class:`Printer` prints ``:`` and the node type after every typed node, - and ``->`` and the node type before the colon in a function definition. - - In almost all cases (except function definition) this does not result - in valid Python syntax. - - :ivar rewriter: (:class:`pythonparser.source.Rewriter`) rewriter instance - """ - - def __init__(self, buf): - self.rewriter = source.Rewriter(buf) - self.type_printer = types.TypePrinter() - - def rewrite(self): - return self.rewriter.rewrite() - - def visit_FunctionDefT(self, node): - super().generic_visit(node) - - self.rewriter.insert_before(node.colon_loc, - "->{}".format(self.type_printer.name(node.return_type))) - - def visit_ExceptHandlerT(self, node): - super().generic_visit(node) - - if node.name_loc: - self.rewriter.insert_after(node.name_loc, - ":{}".format(self.type_printer.name(node.name_type))) - - def visit_ForT(self, node): - super().generic_visit(node) - - if node.trip_count is not None and node.trip_interval is not None: - self.rewriter.insert_after(node.keyword_loc, - "[{} x {} mu]".format(node.trip_count.fold(), - node.trip_interval.fold())) - - def generic_visit(self, node): - super().generic_visit(node) - - if hasattr(node, "type"): - self.rewriter.insert_after(node.loc, - ":{}".format(self.type_printer.name(node.type))) - -def main(): - if len(sys.argv) > 1 and sys.argv[1] == "+mono": - del sys.argv[1] - monomorphize = True - else: - monomorphize = False - - if len(sys.argv) > 1 and sys.argv[1] == "+iodelay": - del sys.argv[1] - iodelay = True - else: - iodelay = False - - if len(sys.argv) > 1 and sys.argv[1] == "+diag": - del sys.argv[1] - def process_diagnostic(diag): - print("\n".join(diag.render(only_line=True))) - if diag.level == "fatal": - exit() - else: - def process_diagnostic(diag): - print("\n".join(diag.render())) - if diag.level in ("fatal", "error"): - exit(1) - - engine = diagnostic.Engine() - engine.process = process_diagnostic - - buf = source.Buffer("".join(fileinput.input()).expandtabs(), - os.path.basename(fileinput.filename())) - parsed, comments = parse_buffer(buf, engine=engine) - typed = ASTTypedRewriter(engine=engine, prelude=prelude.globals()).visit(parsed) - Inferencer(engine=engine).visit(typed) - ConstnessValidator(engine=engine).visit(typed) - if monomorphize: - CastMonomorphizer(engine=engine).visit(typed) - IntMonomorphizer(engine=engine).visit(typed) - Inferencer(engine=engine).visit(typed) - if iodelay: - IODelayEstimator(engine=engine, ref_period=1e6).visit_fixpoint(typed) - - printer = Printer(buf) - printer.visit(typed) - for comment in comments: - if comment.text.find("CHECK") >= 0: - printer.rewriter.remove(comment.loc) - print(printer.rewrite().source) - -if __name__ == "__main__": - main() diff --git a/artiq/compiler/testbench/irgen.py b/artiq/compiler/testbench/irgen.py deleted file mode 100644 index 275f11c94..000000000 --- a/artiq/compiler/testbench/irgen.py +++ /dev/null @@ -1,23 +0,0 @@ -import sys, os, fileinput -from pythonparser import diagnostic -from .. import ir -from ..module import Module, Source - -def main(): - if os.getenv("ARTIQ_IR_NO_LOC") is not None: - ir.BasicBlock._dump_loc = False - - def process_diagnostic(diag): - print("\n".join(diag.render())) - if diag.level in ("fatal", "error"): - exit(1) - - engine = diagnostic.Engine() - engine.process = process_diagnostic - - mod = Module(Source.from_string("".join(fileinput.input()).expandtabs(), engine=engine)) - for fn in mod.artiq_ir: - print(fn) - -if __name__ == "__main__": - main() diff --git a/artiq/compiler/testbench/jit.py b/artiq/compiler/testbench/jit.py deleted file mode 100644 index 67a43c008..000000000 --- a/artiq/compiler/testbench/jit.py +++ /dev/null @@ -1,35 +0,0 @@ -import os, sys, fileinput, ctypes -from pythonparser import diagnostic -from llvmlite import binding as llvm -from ..module import Module, Source -from ..targets import NativeTarget - -def main(): - libartiq_support = os.getenv("LIBARTIQ_SUPPORT") - if libartiq_support is not None: - llvm.load_library_permanently(libartiq_support) - - def process_diagnostic(diag): - print("\n".join(diag.render())) - if diag.level in ("fatal", "error"): - exit(1) - - engine = diagnostic.Engine() - engine.process = process_diagnostic - - source = "".join(fileinput.input()) - source = source.replace("#ARTIQ#", "") - mod = Module(Source.from_string(source.expandtabs(), engine=engine)) - - target = NativeTarget() - llmod = mod.build_llvm_ir(target) - llparsedmod = llvm.parse_assembly(str(llmod)) - llparsedmod.verify() - - llmachine = llvm.Target.from_triple(target.triple).create_target_machine() - lljit = llvm.create_mcjit_compiler(llparsedmod, llmachine) - llmain = lljit.get_function_address(llmod.name + ".__modinit__") - ctypes.CFUNCTYPE(None)(llmain)() - -if __name__ == "__main__": - main() diff --git a/artiq/compiler/testbench/llvmgen.py b/artiq/compiler/testbench/llvmgen.py deleted file mode 100644 index 6bcf031c9..000000000 --- a/artiq/compiler/testbench/llvmgen.py +++ /dev/null @@ -1,31 +0,0 @@ -import sys, fileinput -from pythonparser import diagnostic -from llvmlite import ir as ll -from ..module import Module, Source -from ..targets import NativeTarget - -def main(): - def process_diagnostic(diag): - print("\n".join(diag.render())) - if diag.level in ("fatal", "error"): - exit(1) - - engine = diagnostic.Engine() - engine.process = process_diagnostic - - mod = Module(Source.from_string("".join(fileinput.input()).expandtabs(), engine=engine)) - - target = NativeTarget() - llmod = mod.build_llvm_ir(target=target) - - # Add main so that the result can be executed with lli - llmain = ll.Function(llmod, ll.FunctionType(ll.VoidType(), []), "main") - llbuilder = ll.IRBuilder(llmain.append_basic_block("entry")) - llbuilder.call(llmod.get_global(llmod.name + ".__modinit__"), [ - ll.Constant(ll.IntType(8).as_pointer(), None)]) - llbuilder.ret_void() - - print(llmod) - -if __name__ == "__main__": - main() diff --git a/artiq/compiler/testbench/perf.py b/artiq/compiler/testbench/perf.py deleted file mode 100644 index 363c88840..000000000 --- a/artiq/compiler/testbench/perf.py +++ /dev/null @@ -1,37 +0,0 @@ -import sys, os -from pythonparser import diagnostic -from ..module import Module, Source -from ..targets import RISCVTarget -from . import benchmark - -def main(): - if not len(sys.argv) == 2: - print("Expected exactly one module filename", file=sys.stderr) - exit(1) - - def process_diagnostic(diag): - print("\n".join(diag.render()), file=sys.stderr) - if diag.level in ("fatal", "error"): - exit(1) - - engine = diagnostic.Engine() - engine.process = process_diagnostic - - # Make sure everything's valid - filename = sys.argv[1] - with open(filename) as f: - code = f.read() - source = Source.from_string(code, filename, engine=engine) - module = Module(source) - - benchmark(lambda: Source.from_string(code, filename), - "ARTIQ parsing and inference") - - benchmark(lambda: Module(source), - "ARTIQ transforms and validators") - - benchmark(lambda: RISCVTarget().compile_and_link([module]), - "LLVM optimization and linking") - -if __name__ == "__main__": - main() diff --git a/artiq/compiler/testbench/perf_embedding.py b/artiq/compiler/testbench/perf_embedding.py deleted file mode 100644 index d626d5534..000000000 --- a/artiq/compiler/testbench/perf_embedding.py +++ /dev/null @@ -1,72 +0,0 @@ -import sys, os, tokenize -from pythonparser import diagnostic -from ...language.environment import ProcessArgumentManager -from ...master.databases import DeviceDB, DatasetDB -from ...master.worker_db import DeviceManager, DatasetManager -from ..module import Module -from ..embedding import Stitcher -from ..targets import RISCVTarget -from . import benchmark - - -def main(): - if not len(sys.argv) == 2: - print("Expected exactly one module filename", file=sys.stderr) - exit(1) - - def process_diagnostic(diag): - print("\n".join(diag.render()), file=sys.stderr) - if diag.level in ("fatal", "error"): - exit(1) - - engine = diagnostic.Engine() - engine.process = process_diagnostic - - with tokenize.open(sys.argv[1]) as f: - testcase_code = compile(f.read(), f.name, "exec") - testcase_vars = {'__name__': 'testbench'} - exec(testcase_code, testcase_vars) - - device_db_path = os.path.join(os.path.dirname(sys.argv[1]), "device_db.py") - device_mgr = DeviceManager(DeviceDB(device_db_path)) - - dataset_db_path = os.path.join(os.path.dirname(sys.argv[1]), "dataset_db.pyon") - dataset_mgr = DatasetManager(DatasetDB(dataset_db_path)) - - argument_mgr = ProcessArgumentManager({}) - - def embed(): - experiment = testcase_vars["Benchmark"]((device_mgr, dataset_mgr, argument_mgr)) - - stitcher = Stitcher(core=experiment.core, dmgr=device_mgr) - stitcher.stitch_call(experiment.run, (), {}) - stitcher.finalize() - return stitcher - - stitcher = embed() - module = Module(stitcher) - target = RISCVTarget() - llvm_ir = target.compile(module) - elf_obj = target.assemble(llvm_ir) - elf_shlib = target.link([elf_obj]) - - benchmark(lambda: embed(), - "ARTIQ embedding") - - benchmark(lambda: Module(stitcher), - "ARTIQ transforms and validators") - - benchmark(lambda: target.compile(module), - "LLVM optimizations") - - benchmark(lambda: target.assemble(llvm_ir), - "LLVM machine code emission") - - benchmark(lambda: target.link([elf_obj]), - "Linking") - - benchmark(lambda: target.strip(elf_shlib), - "Stripping debug information") - -if __name__ == "__main__": - main() diff --git a/artiq/compiler/testbench/shlib.py b/artiq/compiler/testbench/shlib.py deleted file mode 100644 index 0aa6386d3..000000000 --- a/artiq/compiler/testbench/shlib.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys, os -from pythonparser import diagnostic -from ..module import Module, Source -from ..targets import RISCVTarget - -def main(): - if not len(sys.argv) > 1: - print("Expected at least one module filename", file=sys.stderr) - exit(1) - - def process_diagnostic(diag): - print("\n".join(diag.render()), file=sys.stderr) - if diag.level in ("fatal", "error"): - exit(1) - - engine = diagnostic.Engine() - engine.process = process_diagnostic - - modules = [] - for filename in sys.argv[1:]: - modules.append(Module(Source.from_filename(filename, engine=engine))) - - llobj = RISCVTarget().compile_and_link(modules) - - basename, ext = os.path.splitext(sys.argv[-1]) - with open(basename + ".so", "wb") as f: - f.write(llobj) - -if __name__ == "__main__": - main() diff --git a/artiq/compiler/testbench/signature.py b/artiq/compiler/testbench/signature.py deleted file mode 100644 index 5d3ff1aa4..000000000 --- a/artiq/compiler/testbench/signature.py +++ /dev/null @@ -1,44 +0,0 @@ -import sys, fileinput -from pythonparser import diagnostic -from ..module import Module, Source -from .. import types, iodelay - -def main(): - if len(sys.argv) > 1 and sys.argv[1] == "+diag": - del sys.argv[1] - diag = True - def process_diagnostic(diag): - print("\n".join(diag.render(only_line=True))) - if diag.level == "fatal": - exit() - else: - diag = False - def process_diagnostic(diag): - print("\n".join(diag.render(colored=False))) - if diag.level in ("fatal", "error"): - exit(1) - - if len(sys.argv) > 1 and sys.argv[1] == "+delay": - del sys.argv[1] - force_delays = True - else: - force_delays = False - - engine = diagnostic.Engine() - engine.process = process_diagnostic - - try: - mod = Module(Source.from_string("".join(fileinput.input()).expandtabs(), engine=engine)) - - if force_delays: - for var in mod.globals: - typ = mod.globals[var].find() - if types.is_function(typ) and types.is_indeterminate_delay(typ.delay): - process_diagnostic(typ.delay.find().cause) - - print(repr(mod)) - except: - if not diag: raise - -if __name__ == "__main__": - main() diff --git a/artiq/compiler/transforms/__init__.py b/artiq/compiler/transforms/__init__.py deleted file mode 100644 index 5696be95f..000000000 --- a/artiq/compiler/transforms/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from .asttyped_rewriter import ASTTypedRewriter -from .inferencer import Inferencer -from .int_monomorphizer import IntMonomorphizer -from .cast_monomorphizer import CastMonomorphizer -from .iodelay_estimator import IODelayEstimator -from .artiq_ir_generator import ARTIQIRGenerator -from .dead_code_eliminator import DeadCodeEliminator -from .local_demoter import LocalDemoter -from .constant_hoister import ConstantHoister -from .interleaver import Interleaver -from .typedtree_printer import TypedtreePrinter -from .llvm_ir_generator import LLVMIRGenerator diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py deleted file mode 100644 index 4520ec049..000000000 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ /dev/null @@ -1,2708 +0,0 @@ -""" -:class:`ARTIQIRGenerator` transforms typed AST into ARTIQ intermediate -representation. ARTIQ IR is designed to be low-level enough that -its operations are elementary--contain no internal branching-- -but without too much detail, such as exposing the reference/value -semantics explicitly. -""" - -from collections import OrderedDict, defaultdict -from functools import reduce -from pythonparser import algorithm, diagnostic, ast -from .. import types, builtins, asttyped, ir, iodelay - -def _readable_name(insn): - if isinstance(insn, ir.Constant): - return str(insn.value) - else: - return insn.name - -def _extract_loc(node): - if "keyword_loc" in node._locs: - return node.keyword_loc - else: - return node.loc - -# We put some effort in keeping generated IR readable, -# i.e. with a more or less linear correspondence to the source. -# This is why basic blocks sometimes seem to be produced in an odd order. -class ARTIQIRGenerator(algorithm.Visitor): - """ - :class:`ARTIQIRGenerator` contains a lot of internal state, - which is effectively maintained in a stack--with push/pop - pairs around any state updates. It is comprised of following: - - :ivar current_loc: (:class:`pythonparser.source.Range`) - source range of the node being currently visited - :ivar current_function: (:class:`ir.Function` or None) - module, def or lambda currently being translated - :ivar current_globals: (set of string) - set of variables that will be resolved in global scope - :ivar current_block: (:class:`ir.BasicBlock`) - basic block to which any new instruction will be appended - :ivar current_env: (:class:`ir.Alloc` of type :class:`ir.TEnvironment`) - the chained function environment, containing variables that - can become upvalues - :ivar current_private_env: (:class:`ir.Alloc` of type :class:`ir.TEnvironment`) - the private function environment, containing internal state - :ivar current_args: (dict of string to :class:`ir.Argument`) - the map of Python names of formal arguments to - the current function to their SSA names - :ivar current_assign: (:class:`ir.Value` or None) - the right-hand side of current assignment statement, or - a component of a composite right-hand side when visiting - a composite left-hand side, such as, in ``x, y = z``, - the 2nd tuple element when visting ``y`` - :ivar break_target: (:class:`ir.BasicBlock` or None) - the basic block to which ``break`` will transfer control - :ivar continue_target: (:class:`ir.BasicBlock` or None) - the basic block to which ``continue`` will transfer control - :ivar return_target: (:class:`ir.BasicBlock` or None) - the basic block to which ``return`` will transfer control - :ivar unwind_target: (:class:`ir.BasicBlock` or None) - the basic block to which unwinding will transfer control - :ivar final_branch: (function (target: :class:`ir.BasicBlock`, block: :class:`ir.BasicBlock) - or None) - the function that appends to ``block`` a jump through the ``finally`` statement - to ``target`` - - There is, additionally, some global state that is used to translate - the results of analyses on AST level to IR level: - - :ivar function_map: (map of :class:`ast.FunctionDefT` to :class:`ir.Function`) - the map from function definition nodes to IR functions - :ivar variable_map: (map of :class:`ast.NameT` to :class:`ir.GetLocal`) - the map from variable name nodes to instructions retrieving - the variable values - :ivar method_map: (map of :class:`ast.AttributeT` to :class:`ir.GetAttribute`) - the map from method resolution nodes to instructions retrieving - the called function inside a translated :class:`ast.CallT` node - - Finally, functions that implement array operations are instantiated on the fly as - necessary. They are kept track of in global dictionaries, with a mangled name - containing types and operations as key: - - :ivar array_op_funcs: the map from mangled name to implementation of - operations on/between arrays - """ - - _size_type = builtins.TInt32() - - def __init__(self, module_name, engine, ref_period): - self.engine = engine - self.functions = [] - self.name = [module_name] if module_name != "" else [] - self.ref_period = ir.Constant(ref_period, builtins.TFloat()) - self.current_loc = None - self.current_function = None - self.current_class = None - self.current_globals = set() - self.current_block = None - self.current_env = None - self.current_private_env = None - self.current_args = None - self.current_assign = None - self.break_target = None - self.continue_target = None - self.return_target = None - self.unwind_target = None - self.final_branch = None - self.function_map = dict() - self.variable_map = dict() - self.method_map = defaultdict(lambda: []) - self.array_op_funcs = dict() - self.raise_assert_func = None - - def annotate_calls(self, devirtualization): - for var_node in devirtualization.variable_map: - callee_node = devirtualization.variable_map[var_node] - if callee_node is None: - continue - callee = self.function_map[callee_node] - - call_target = self.variable_map[var_node] - for use in call_target.uses: - if isinstance(use, (ir.Call, ir.Invoke)) and \ - use.target_function() == call_target: - use.static_target_function = callee - - for type_and_method in devirtualization.method_map: - callee_node = devirtualization.method_map[type_and_method] - if callee_node is None: - continue - callee = self.function_map[callee_node] - - for call in self.method_map[type_and_method]: - assert isinstance(call, (ir.Call, ir.Invoke)) - call.static_target_function = callee - - def add_block(self, name=""): - block = ir.BasicBlock([], name) - self.current_function.add(block) - return block - - def append(self, insn, block=None, loc=None): - if loc is None: - loc = self.current_loc - if block is None: - block = self.current_block - - if insn.loc is None: - insn.loc = loc - return block.append(insn) - - def terminate(self, insn): - if not self.current_block.is_terminated(): - self.append(insn) - else: - insn.drop_references() - - def warn_unreachable(self, node): - diag = diagnostic.Diagnostic("warning", - "unreachable code", {}, - node.loc.begin()) - self.engine.process(diag) - - # Visitors - - def visit(self, obj): - if isinstance(obj, list): - for elt in obj: - if self.current_block.is_terminated(): - self.warn_unreachable(elt) - break - self.visit(elt) - elif isinstance(obj, ast.AST): - try: - old_loc, self.current_loc = self.current_loc, _extract_loc(obj) - return self._visit_one(obj) - finally: - self.current_loc = old_loc - - # Module visitor - - def visit_ModuleT(self, node): - # Treat start of module as synthesized - self.current_loc = None - - try: - typ = types.TFunction(OrderedDict(), OrderedDict(), builtins.TNone()) - func = ir.Function(typ, ".".join(self.name + ['__modinit__']), [], - loc=node.loc.begin()) - self.functions.append(func) - old_func, self.current_function = self.current_function, func - - entry = self.add_block("entry") - old_block, self.current_block = self.current_block, entry - - env_type = ir.TEnvironment(name=func.name, vars=node.typing_env) - env = self.append(ir.Alloc([], env_type, name="env")) - old_env, self.current_env = self.current_env, env - - priv_env_type = ir.TEnvironment(name=func.name + ".priv", vars={ "$return": typ.ret }) - priv_env = self.append(ir.Alloc([], priv_env_type, name="privenv")) - old_priv_env, self.current_private_env = self.current_private_env, priv_env - - self.generic_visit(node) - self.terminate(ir.Return(ir.Constant(None, builtins.TNone()))) - - return self.functions - finally: - self.current_function = old_func - self.current_block = old_block - self.current_env = old_env - self.current_private_env = old_priv_env - - # Statement visitors - - def visit_ClassDefT(self, node): - klass = self.append(ir.Alloc([], node.constructor_type, - name="class.{}".format(node.name))) - self._set_local(node.name, klass) - - try: - old_class, self.current_class = self.current_class, klass - self.visit(node.body) - finally: - self.current_class = old_class - - def visit_function(self, node, is_lambda=False, is_internal=False, is_quoted=False, - flags={}): - if is_lambda: - name = "lambda@{}:{}".format(node.loc.line(), node.loc.column()) - typ = node.type.find() - else: - name = node.name - typ = node.signature_type.find() - - try: - defaults = [] - if not is_quoted: - for arg_name, default_node in zip(typ.optargs, node.args.defaults): - default = self.visit(default_node) - env_default_name = \ - self.current_env.type.add("$default." + arg_name, default.type) - self.append(ir.SetLocal(self.current_env, env_default_name, default)) - def codegen_default(env_default_name): - return lambda: self.append(ir.GetLocal(self.current_env, env_default_name)) - defaults.append(codegen_default(env_default_name)) - else: - for default_node in node.args.defaults: - def codegen_default(default_node): - return lambda: self.visit(default_node) - defaults.append(codegen_default(default_node)) - - old_name, self.name = self.name, self.name + [name] - - env_arg = ir.EnvironmentArgument(self.current_env.type, "ARG.ENV") - - old_args, self.current_args = self.current_args, {} - - args = [] - for arg_name in typ.args: - arg = ir.Argument(typ.args[arg_name], "ARG." + arg_name) - self.current_args[arg_name] = arg - args.append(arg) - - optargs = [] - for arg_name in typ.optargs: - arg = ir.Argument(ir.TOption(typ.optargs[arg_name]), "ARG." + arg_name) - self.current_args[arg_name] = arg - optargs.append(arg) - - for (arg, arg_node) in zip(args + optargs, node.args.args): - arg.loc = arg_node.loc - - func = ir.Function(typ, ".".join(self.name), [env_arg] + args + optargs, - loc=node.lambda_loc if is_lambda else node.keyword_loc) - func.is_internal = is_internal - func.flags = flags - self.functions.append(func) - old_func, self.current_function = self.current_function, func - - if not is_lambda: - self.function_map[node] = func - - entry = self.add_block("entry") - old_block, self.current_block = self.current_block, entry - - old_globals, self.current_globals = self.current_globals, node.globals_in_scope - - env_without_globals = \ - {var: node.typing_env[var] - for var in node.typing_env - if var not in node.globals_in_scope} - env_type = ir.TEnvironment(name=func.name, - vars=env_without_globals, outer=self.current_env.type) - env = self.append(ir.Alloc([], env_type, name="ENV")) - old_env, self.current_env = self.current_env, env - - if not is_lambda: - priv_env_type = ir.TEnvironment(name="{}.private".format(func.name), - vars={ "$return": typ.ret }) - priv_env = self.append(ir.Alloc([], priv_env_type, name="PRV")) - old_priv_env, self.current_private_env = self.current_private_env, priv_env - - self.append(ir.SetLocal(env, "$outer", env_arg)) - for index, arg_name in enumerate(typ.args): - self.append(ir.SetLocal(env, arg_name, args[index])) - for index, (arg_name, codegen_default) in enumerate(zip(typ.optargs, defaults)): - default = codegen_default() - value = self.append(ir.Builtin("unwrap_or", [optargs[index], default], - typ.optargs[arg_name], - name="DEF.{}".format(arg_name))) - self.append(ir.SetLocal(env, arg_name, value)) - - result = self.visit(node.body) - - if is_lambda: - self.terminate(ir.Return(result)) - elif builtins.is_none(typ.ret): - if not self.current_block.is_terminated(): - self.current_block.append(ir.Return(ir.Constant(None, builtins.TNone()))) - else: - if not self.current_block.is_terminated(): - if len(self.current_block.predecessors()) != 0: - diag = diagnostic.Diagnostic("error", - "this function must return a value of type {typ} explicitly", - {"typ": types.TypePrinter().name(typ.ret)}, - node.keyword_loc) - self.engine.process(diag) - - self.current_block.append(ir.Unreachable()) - - finally: - self.name = old_name - self.current_args = old_args - self.current_function = old_func - self.current_block = old_block - self.current_globals = old_globals - self.current_env = old_env - if not is_lambda: - self.current_private_env = old_priv_env - - return self.append(ir.Closure(func, self.current_env)) - - def visit_FunctionDefT(self, node): - func = self.visit_function(node, is_internal=len(self.name) > 0) - if self.current_class is None: - self._set_local(node.name, func) - else: - self.append(ir.SetAttr(self.current_class, node.name, func)) - - def visit_QuotedFunctionDefT(self, node): - self.visit_function(node, is_internal=True, is_quoted=True, flags=node.flags) - - def visit_Return(self, node): - if node.value is None: - return_value = ir.Constant(None, builtins.TNone()) - else: - return_value = self.visit(node.value) - - if self.return_target is None: - self.append(ir.Return(return_value)) - else: - self.append(ir.SetLocal(self.current_private_env, "$return", return_value)) - self.append(ir.Branch(self.return_target)) - - def visit_Expr(self, node): - # Ignore the value, do it for side effects. - result = self.visit(node.value) - - # See comment in visit_Pass. - if isinstance(result, ir.Constant): - self.visit_Pass(node) - - def visit_Pass(self, node): - # Insert a dummy instruction so that analyses which extract - # locations from CFG have something to use. - self.append(ir.Builtin("nop", [], builtins.TNone())) - - def visit_Assign(self, node): - try: - self.current_assign = self.visit(node.value) - assert self.current_assign is not None - for target in node.targets: - self.visit(target) - finally: - self.current_assign = None - - def visit_AugAssign(self, node): - lhs = self.visit(node.target) - rhs = self.visit(node.value) - - if builtins.is_array(lhs.type): - name = type(node.op).__name__ - def make_op(l, r): - return self.append(ir.Arith(node.op, l, r)) - self._broadcast_binop(name, make_op, lhs.type, lhs, rhs, assign_to_lhs=True) - return - - value = self.append(ir.Arith(node.op, lhs, rhs)) - try: - self.current_assign = value - self.visit(node.target) - finally: - self.current_assign = None - - def coerce_to_bool(self, insn, block=None): - if builtins.is_bool(insn.type): - return insn - elif builtins.is_int(insn.type): - return self.append(ir.Compare(ast.NotEq(loc=None), insn, ir.Constant(0, insn.type)), - block=block) - elif builtins.is_float(insn.type): - return self.append(ir.Compare(ast.NotEq(loc=None), insn, ir.Constant(0, insn.type)), - block=block) - elif builtins.is_iterable(insn.type): - length = self.iterable_len(insn) - return self.append(ir.Compare(ast.NotEq(loc=None), length, ir.Constant(0, length.type)), - block=block) - elif builtins.is_none(insn.type): - return ir.Constant(False, builtins.TBool()) - else: - note = diagnostic.Diagnostic("note", - "this expression has type {type}", - {"type": types.TypePrinter().name(insn.type)}, - insn.loc) - diag = diagnostic.Diagnostic("warning", - "this expression, which is always truthful, is coerced to bool", {}, - insn.loc, notes=[note]) - self.engine.process(diag) - return ir.Constant(True, builtins.TBool()) - - def visit_If(self, node): - cond = self.visit(node.test) - cond = self.coerce_to_bool(cond) - head = self.current_block - - if_true = self.add_block("if.body") - self.current_block = if_true - self.visit(node.body) - post_if_true = self.current_block - - if any(node.orelse): - if_false = self.add_block("if.else") - self.current_block = if_false - self.visit(node.orelse) - post_if_false = self.current_block - - tail = self.add_block("if.tail") - self.current_block = tail - if not post_if_true.is_terminated(): - post_if_true.append(ir.Branch(tail)) - - if any(node.orelse): - if not post_if_false.is_terminated(): - post_if_false.append(ir.Branch(tail)) - self.append(ir.BranchIf(cond, if_true, if_false), block=head) - else: - self.append(ir.BranchIf(cond, if_true, tail), block=head) - - def visit_While(self, node): - try: - head = self.add_block("while.head") - self.append(ir.Branch(head)) - self.current_block = head - old_continue, self.continue_target = self.continue_target, head - cond = self.visit(node.test) - cond = self.coerce_to_bool(cond) - post_head = self.current_block - - break_block = self.add_block("while.break") - old_break, self.break_target = self.break_target, break_block - - body = self.add_block("while.body") - self.current_block = body - self.visit(node.body) - post_body = self.current_block - finally: - self.break_target = old_break - self.continue_target = old_continue - - if any(node.orelse): - else_tail = self.add_block("while.else") - self.current_block = else_tail - self.visit(node.orelse) - post_else_tail = self.current_block - - tail = self.add_block("while.tail") - self.current_block = tail - - if any(node.orelse): - if not post_else_tail.is_terminated(): - post_else_tail.append(ir.Branch(tail)) - else: - else_tail = tail - - post_head.append(ir.BranchIf(cond, body, else_tail)) - if not post_body.is_terminated(): - post_body.append(ir.Branch(head)) - break_block.append(ir.Branch(tail)) - - def iterable_len(self, value, typ=_size_type): - if builtins.is_listish(value.type): - if isinstance(value, ir.Constant): - name = None - else: - name = "{}.len".format(value.name) - len = self.append(ir.Builtin("len", [value], builtins.TInt32(), - name=name)) - return self.append(ir.Coerce(len, typ)) - elif builtins.is_range(value.type): - start = self.append(ir.GetAttr(value, "start")) - stop = self.append(ir.GetAttr(value, "stop")) - step = self.append(ir.GetAttr(value, "step")) - spread = self.append(ir.Arith(ast.Sub(loc=None), stop, start)) - return self.append(ir.Arith(ast.FloorDiv(loc=None), spread, step, - name="{}.len".format(value.name))) - else: - assert False - - def iterable_get(self, value, index): - # Assuming the value is within bounds. - if builtins.is_array(value.type): - # Scalar indexing into ndarray. - num_dims = value.type.find()["num_dims"].value - if num_dims > 1: - old_shape = self.append(ir.GetAttr(value, "shape")) - lengths = [self.append(ir.GetAttr(old_shape, i)) for i in range(1, num_dims)] - new_shape = self._make_array_shape(lengths) - - stride = reduce( - lambda l, r: self.append(ir.Arith(ast.Mult(loc=None), l, r)), - lengths[1:], lengths[0]) - offset = self.append(ir.Arith(ast.Mult(loc=None), stride, index)) - old_buffer = self.append(ir.GetAttr(value, "buffer")) - new_buffer = self.append(ir.Offset(old_buffer, offset)) - - result_type = builtins.TArray(value.type.find()["elt"], - types.TValue(num_dims - 1)) - return self.append(ir.Alloc([new_buffer, new_shape], result_type)) - else: - buffer = self.append(ir.GetAttr(value, "buffer")) - return self.append(ir.GetElem(buffer, index)) - elif builtins.is_listish(value.type): - return self.append(ir.GetElem(value, index)) - elif builtins.is_range(value.type): - start = self.append(ir.GetAttr(value, "start")) - step = self.append(ir.GetAttr(value, "step")) - offset = self.append(ir.Arith(ast.Mult(loc=None), step, index)) - return self.append(ir.Arith(ast.Add(loc=None), start, offset)) - else: - assert False - - def visit_ForT(self, node): - try: - iterable = self.visit(node.iter) - length = self.iterable_len(iterable) - prehead = self.current_block - - head = self.add_block("for.head") - self.append(ir.Branch(head)) - self.current_block = head - phi = self.append(ir.Phi(length.type, name="IND")) - phi.add_incoming(ir.Constant(0, phi.type), prehead) - cond = self.append(ir.Compare(ast.Lt(loc=None), phi, length, name="CMP")) - - break_block = self.add_block("for.break") - old_break, self.break_target = self.break_target, break_block - - continue_block = self.add_block("for.continue") - old_continue, self.continue_target = self.continue_target, continue_block - self.current_block = continue_block - - updated_index = self.append(ir.Arith(ast.Add(loc=None), phi, ir.Constant(1, phi.type), - name="IND.new")) - phi.add_incoming(updated_index, continue_block) - self.append(ir.Branch(head)) - - body = self.add_block("for.body") - self.current_block = body - elt = self.iterable_get(iterable, phi) - try: - self.current_assign = elt - self.visit(node.target) - finally: - self.current_assign = None - self.visit(node.body) - post_body = self.current_block - finally: - self.break_target = old_break - self.continue_target = old_continue - - if any(node.orelse): - else_tail = self.add_block("for.else") - self.current_block = else_tail - self.visit(node.orelse) - post_else_tail = self.current_block - - tail = self.add_block("for.tail") - self.current_block = tail - - if any(node.orelse): - if not post_else_tail.is_terminated(): - post_else_tail.append(ir.Branch(tail)) - else: - else_tail = tail - - if node.trip_count is not None: - head.append(ir.Loop(node.trip_count, phi, cond, body, else_tail)) - else: - head.append(ir.BranchIf(cond, body, else_tail)) - if not post_body.is_terminated(): - post_body.append(ir.Branch(continue_block)) - break_block.append(ir.Branch(tail)) - - def visit_Break(self, node): - self.append(ir.Branch(self.break_target)) - - def visit_Continue(self, node): - self.append(ir.Branch(self.continue_target)) - - def raise_exn(self, exn=None, loc=None): - if self.final_branch is not None: - raise_proxy = self.add_block("try.raise") - self.final_branch(raise_proxy, self.current_block) - self.current_block = raise_proxy - - if exn is not None: - assert loc is not None - loc_file = ir.Constant(loc.source_buffer.name, builtins.TStr()) - loc_line = ir.Constant(loc.line(), builtins.TInt32()) - loc_column = ir.Constant(loc.column(), builtins.TInt32()) - loc_function = ir.Constant(".".join(self.name), builtins.TStr()) - - self.append(ir.SetAttr(exn, "__file__", loc_file)) - self.append(ir.SetAttr(exn, "__line__", loc_line)) - self.append(ir.SetAttr(exn, "__col__", loc_column)) - self.append(ir.SetAttr(exn, "__func__", loc_function)) - - if self.unwind_target is not None: - self.append(ir.Raise(exn, self.unwind_target)) - else: - self.append(ir.Raise(exn)) - else: - if self.unwind_target is not None: - self.append(ir.Reraise(self.unwind_target)) - else: - self.append(ir.Reraise()) - - def visit_Raise(self, node): - if node.exc is not None and types.is_exn_constructor(node.exc.type): - self.raise_exn(self.alloc_exn(node.exc.type.instance), loc=self.current_loc) - else: - self.raise_exn(self.visit(node.exc), loc=self.current_loc) - - def visit_Try(self, node): - dispatcher = self.add_block("try.dispatch") - - if any(node.finalbody): - # k for continuation - final_suffix = ".try@{}:{}".format(node.loc.line(), node.loc.column()) - final_env_type = ir.TEnvironment(name=self.current_function.name + final_suffix, - vars={ "$cont": ir.TBasicBlock() }) - final_state = self.append(ir.Alloc([], final_env_type)) - final_targets = [] - final_paths = [] - - def final_branch(target, block): - block.append(ir.SetLocal(final_state, "$cont", target)) - final_targets.append(target) - final_paths.append(block) - - if self.break_target is not None: - break_proxy = self.add_block("try.break") - old_break, self.break_target = self.break_target, break_proxy - final_branch(old_break, break_proxy) - - if self.continue_target is not None: - continue_proxy = self.add_block("try.continue") - old_continue, self.continue_target = self.continue_target, continue_proxy - final_branch(old_continue, continue_proxy) - - return_proxy = self.add_block("try.return") - old_return, self.return_target = self.return_target, return_proxy - if old_return is not None: - final_branch(old_return, return_proxy) - else: - return_action = self.add_block("try.doreturn") - value = return_action.append(ir.GetLocal(self.current_private_env, "$return")) - return_action.append(ir.Return(value)) - final_branch(return_action, return_proxy) - - body = self.add_block("try.body") - self.append(ir.Branch(body)) - self.current_block = body - - try: - old_unwind, self.unwind_target = self.unwind_target, dispatcher - self.visit(node.body) - finally: - self.unwind_target = old_unwind - - if not self.current_block.is_terminated(): - self.visit(node.orelse) - elif any(node.orelse): - self.warn_unreachable(node.orelse[0]) - body = self.current_block - - if any(node.finalbody): - if self.break_target: - self.break_target = old_break - if self.continue_target: - self.continue_target = old_continue - self.return_target = old_return - - old_final_branch, self.final_branch = self.final_branch, final_branch - - cleanup = self.add_block('handler.cleanup') - landingpad = dispatcher.append(ir.LandingPad(cleanup)) - - handlers = [] - for handler_node in node.handlers: - exn_type = handler_node.name_type.find() - if handler_node.filter is not None and \ - not builtins.is_exception(exn_type, 'Exception'): - handler = self.add_block("handler." + exn_type.name) - landingpad.add_clause(handler, exn_type) - else: - handler = self.add_block("handler.catchall") - landingpad.add_clause(handler, None) - - self.current_block = handler - if handler_node.name is not None: - exn = self.append(ir.Builtin("exncast", [landingpad], handler_node.name_type)) - self._set_local(handler_node.name, exn) - self.visit(handler_node.body) - post_handler = self.current_block - - handlers.append((handler, post_handler)) - - if any(node.finalbody): - # Finalize and continue after try statement. - self.final_branch = old_final_branch - - finalizer = self.add_block("finally") - self.current_block = finalizer - - self.visit(node.finalbody) - post_finalizer = self.current_block - - # Finalize and reraise. Separate from previous case to expose flow - # to LocalAccessValidator. - finalizer_reraise = self.add_block("finally.reraise") - self.current_block = finalizer_reraise - - self.visit(node.finalbody) - self.terminate(ir.Reraise(self.unwind_target)) - - self.current_block = tail = self.add_block("try.tail") - if any(node.finalbody): - final_targets.append(tail) - - for block in final_paths: - block.append(ir.Branch(finalizer)) - - if not body.is_terminated(): - body.append(ir.SetLocal(final_state, "$cont", tail)) - body.append(ir.Branch(finalizer)) - - cleanup.append(ir.Branch(finalizer_reraise)) - - for handler, post_handler in handlers: - if not post_handler.is_terminated(): - post_handler.append(ir.SetLocal(final_state, "$cont", tail)) - post_handler.append(ir.Branch(finalizer)) - - if not post_finalizer.is_terminated(): - dest = post_finalizer.append(ir.GetLocal(final_state, "$cont")) - post_finalizer.append(ir.IndirectBranch(dest, final_targets)) - else: - if not body.is_terminated(): - body.append(ir.Branch(tail)) - - cleanup.append(ir.Reraise(self.unwind_target)) - - for handler, post_handler in handlers: - if not post_handler.is_terminated(): - post_handler.append(ir.Branch(tail)) - - def _try_finally(self, body_gen, finally_gen, name): - dispatcher = self.add_block("{}.dispatch".format(name)) - - try: - old_unwind, self.unwind_target = self.unwind_target, dispatcher - body_gen() - finally: - self.unwind_target = old_unwind - - if not self.current_block.is_terminated(): - finally_gen() - - self.post_body = self.current_block - - self.current_block = self.add_block("{}.cleanup".format(name)) - dispatcher.append(ir.LandingPad(self.current_block)) - finally_gen() - self.raise_exn() - - self.current_block = self.post_body - - def visit_With(self, node): - context_expr_node = node.items[0].context_expr - optional_vars_node = node.items[0].optional_vars - - if types.is_builtin(context_expr_node.type, "sequential"): - self.visit(node.body) - return - elif types.is_builtin(context_expr_node.type, "interleave"): - interleave = self.append(ir.Interleave([])) - - heads, tails = [], [] - for stmt in node.body: - self.current_block = self.add_block("interleave.branch") - heads.append(self.current_block) - self.visit(stmt) - tails.append(self.current_block) - - for head in heads: - interleave.add_destination(head) - - self.current_block = self.add_block("interleave.tail") - for tail in tails: - if not tail.is_terminated(): - tail.append(ir.Branch(self.current_block)) - return - elif types.is_builtin(context_expr_node.type, "parallel"): - start_mu = self.append(ir.Builtin("now_mu", [], builtins.TInt64())) - end_mu = start_mu - - for stmt in node.body: - self.append(ir.Builtin("at_mu", [start_mu], builtins.TNone())) - - block = self.add_block("parallel.branch") - if self.current_block.is_terminated(): - self.warn_unreachable(stmt[0]) - else: - self.append(ir.Branch(block)) - self.current_block = block - - self.visit(stmt) - - mid_mu = self.append(ir.Builtin("now_mu", [], builtins.TInt64())) - gt_mu = self.append(ir.Compare(ast.Gt(loc=None), mid_mu, end_mu)) - end_mu = self.append(ir.Select(gt_mu, mid_mu, end_mu)) - - self.append(ir.Builtin("at_mu", [end_mu], builtins.TNone())) - return - - cleanup = [] - for item_node in node.items: - # user-defined context manager - context_expr_node = item_node.context_expr - optional_vars_node = item_node.optional_vars - context_mgr = self.visit(context_expr_node) - enter_fn = self.append(ir.GetAttr(context_mgr, '__enter__')) - exit_fn = self.append(ir.GetAttr(context_mgr, '__exit__')) - - try: - self.current_assign = self._user_call(enter_fn, [], {}) - if optional_vars_node is not None: - self.visit(optional_vars_node) - finally: - self.current_assign = None - - none = self.append(ir.Alloc([], builtins.TNone())) - cleanup.append(lambda: - self._user_call(exit_fn, [none, none, none], {})) - - self._try_finally( - body_gen=lambda: self.visit(node.body), - finally_gen=lambda: [thunk() for thunk in cleanup], - name="with") - - # Expression visitors - # These visitors return a node in addition to mutating - # the IR. - - def visit_LambdaT(self, node): - return self.visit_function(node, is_lambda=True, is_internal=True) - - def visit_IfExpT(self, node): - cond = self.visit(node.test) - head = self.current_block - - if_true = self.add_block("ifexp.body") - self.current_block = if_true - true_result = self.visit(node.body) - post_if_true = self.current_block - - if_false = self.add_block("ifexp.else") - self.current_block = if_false - false_result = self.visit(node.orelse) - post_if_false = self.current_block - - tail = self.add_block("ifexp.tail") - self.current_block = tail - - if not post_if_true.is_terminated(): - post_if_true.append(ir.Branch(tail)) - if not post_if_false.is_terminated(): - post_if_false.append(ir.Branch(tail)) - head.append(ir.BranchIf(cond, if_true, if_false)) - - phi = self.append(ir.Phi(node.type)) - phi.add_incoming(true_result, post_if_true) - phi.add_incoming(false_result, post_if_false) - return phi - - def visit_NumT(self, node): - return ir.Constant(node.n, node.type) - - def visit_StrT(self, node): - return ir.Constant(node.s, node.type) - - def visit_NameConstantT(self, node): - return ir.Constant(node.value, node.type) - - def _env_for(self, name): - if name in self.current_globals: - return self.append(ir.Builtin("globalenv", [self.current_env], - self.current_env.type.outermost())) - else: - return self.current_env - - def _get_local(self, name): - if self.current_class is not None and \ - name in self.current_class.type.attributes: - return self.append(ir.GetAttr(self.current_class, name, - name="FLD." + name)) - - return self.append(ir.GetLocal(self._env_for(name), name, - name="LOC." + name)) - - def _set_local(self, name, value): - if self.current_class is not None and \ - name in self.current_class.type.attributes: - return self.append(ir.SetAttr(self.current_class, name, value)) - - self.append(ir.SetLocal(self._env_for(name), name, value)) - - def visit_NameT(self, node): - if self.current_assign is None: - insn = self._get_local(node.id) - self.variable_map[node] = insn - return insn - else: - return self._set_local(node.id, self.current_assign) - - def visit_AttributeT(self, node): - try: - old_assign, self.current_assign = self.current_assign, None - obj = self.visit(node.value) - finally: - self.current_assign = old_assign - - if self.current_assign is None: - return self.append(ir.GetAttr(obj, node.attr, - name="{}.FLD.{}".format(_readable_name(obj), node.attr))) - else: - return self.append(ir.SetAttr(obj, node.attr, self.current_assign)) - - def _make_check(self, cond, exn_gen, loc=None, params=[]): - if loc is None: - loc = self.current_loc - - try: - name = "check:{}:{}".format(loc.line(), loc.column()) - args = [ir.EnvironmentArgument(self.current_env.type, "ARG.ENV")] + \ - [ir.Argument(param.type, "ARG.{}".format(index)) - for index, param in enumerate(params)] - typ = types.TFunction(OrderedDict([("arg{}".format(index), param.type) - for index, param in enumerate(params)]), - OrderedDict(), - builtins.TNone()) - func = ir.Function(typ, ".".join(self.name + [name]), args, loc=loc) - func.is_internal = True - func.is_cold = True - func.is_generated = True - self.functions.append(func) - old_func, self.current_function = self.current_function, func - - entry = self.add_block("entry") - old_block, self.current_block = self.current_block, entry - - old_final_branch, self.final_branch = self.final_branch, None - old_unwind, self.unwind_target = self.unwind_target, None - self.raise_exn(exn_gen(*args[1:]), loc=loc) - finally: - self.current_function = old_func - self.current_block = old_block - self.final_branch = old_final_branch - self.unwind_target = old_unwind - - # cond: bool Value, condition - # exn_gen: lambda()->exn Value, exception if condition not true - cond_block = self.current_block - - self.current_block = body_block = self.add_block("check.body") - self._invoke_raising_func(func, params, "check") - - self.current_block = tail_block = self.add_block("check.tail") - cond_block.append(ir.BranchIf(cond, tail_block, body_block)) - - def _invoke_raising_func(self, func, params, block_name): - """Emit a call/invoke instruction as appropriate to terminte the current - basic block with a call to a helper function that always raises an - exception. - - (This is done for compiler-inserted checks and assertions to keep the - generated code tight for the normal case.) - """ - closure = self.append(ir.Closure(func, - ir.Constant(None, ir.TEnvironment("raise", {})))) - if self.unwind_target is None: - insn = self.append(ir.Call(closure, params, {})) - else: - after_invoke = self.add_block(block_name + ".invoke") - insn = self.append(ir.Invoke(closure, params, {}, after_invoke, self.unwind_target)) - self.current_block = after_invoke - insn.is_cold = True - self.append(ir.Unreachable()) - - def _map_index(self, length, index, one_past_the_end=False, loc=None): - lt_0 = self.append(ir.Compare(ast.Lt(loc=None), - index, ir.Constant(0, index.type))) - from_end = self.append(ir.Arith(ast.Add(loc=None), length, index)) - mapped_index = self.append(ir.Select(lt_0, from_end, index)) - mapped_ge_0 = self.append(ir.Compare(ast.GtE(loc=None), - mapped_index, ir.Constant(0, mapped_index.type))) - end_cmpop = ast.LtE(loc=None) if one_past_the_end else ast.Lt(loc=None) - mapped_lt_len = self.append(ir.Compare(end_cmpop, mapped_index, length)) - in_bounds = self.append(ir.Select(mapped_ge_0, mapped_lt_len, - ir.Constant(False, builtins.TBool()))) - head = self.current_block - - self._make_check( - in_bounds, - lambda index, length: self.alloc_exn(builtins.TException("IndexError"), - ir.Constant("index {0} out of bounds 0:{1}", builtins.TStr()), - index, length), - params=[index, length], - loc=loc) - - return mapped_index - - def _make_loop(self, init, cond_gen, body_gen, name="loop"): - # init: 'iter Value, initial loop variable value - # cond_gen: lambda('iter Value)->bool Value, loop condition - # body_gen: lambda('iter Value)->'iter Value, loop body, - # returns next loop variable value - init_block = self.current_block - - self.current_block = head_block = self.add_block("{}.head".format(name)) - init_block.append(ir.Branch(head_block)) - phi = self.append(ir.Phi(init.type)) - phi.add_incoming(init, init_block) - cond = cond_gen(phi) - - self.current_block = body_block = self.add_block("{}.body".format(name)) - body = body_gen(phi) - self.append(ir.Branch(head_block)) - phi.add_incoming(body, self.current_block) - - self.current_block = tail_block = self.add_block("{}.tail".format(name)) - head_block.append(ir.BranchIf(cond, body_block, tail_block)) - - return head_block, body_block, tail_block - - def visit_SubscriptT(self, node): - try: - old_assign, self.current_assign = self.current_assign, None - value = self.visit(node.value) - finally: - self.current_assign = old_assign - - if isinstance(node.slice, ast.Index): - try: - old_assign, self.current_assign = self.current_assign, None - index = self.visit(node.slice.value) - finally: - self.current_assign = old_assign - - # For multi-dimensional indexes, just apply them sequentially. This - # works, as they are only supported for types where we do not - # immediately need to distinguish between the Get and Set cases - # (i.e. arrays, which are reference types). - if types.is_tuple(index.type): - num_idxs = len(index.type.find().elts) - indices = [ - self.append(ir.GetAttr(index, i)) for i in range(num_idxs) - ] - else: - indices = [index] - indexed = value - for i, idx in enumerate(indices): - length = self.iterable_len(indexed, idx.type) - mapped_index = self._map_index(length, idx, loc=node.begin_loc) - if self.current_assign is None or i < len(indices) - 1: - indexed = self.iterable_get(indexed, mapped_index) - indexed.set_name("{}.at.{}".format(indexed.name, - _readable_name(idx))) - else: - self.append(ir.SetElem(indexed, mapped_index, self.current_assign, - name="{}.at.{}".format(value.name, - _readable_name(index)))) - if self.current_assign is None: - return indexed - else: - # This is a slice. The endpoint checking logic is the same for both lists - # and NumPy arrays, but the actual implementations differ – while slices of - # built-in lists are always copies in Python, they are views sharing the - # same backing storage in NumPy. - length = self.iterable_len(value, node.slice.type) - - if node.slice.lower is not None: - try: - old_assign, self.current_assign = self.current_assign, None - start_index = self.visit(node.slice.lower) - finally: - self.current_assign = old_assign - else: - start_index = ir.Constant(0, node.slice.type) - mapped_start_index = self._map_index(length, start_index, - loc=node.begin_loc) - - if node.slice.upper is not None: - try: - old_assign, self.current_assign = self.current_assign, None - stop_index = self.visit(node.slice.upper) - finally: - self.current_assign = old_assign - else: - stop_index = length - mapped_stop_index = self._map_index(length, stop_index, one_past_the_end=True, - loc=node.begin_loc) - - if builtins.is_array(node.type): - # To implement strided slicing with the proper NumPy reference - # semantics, the pointer/length array representation will need to be - # extended by another field to hold a variable stride. - assert node.slice.step is None, ( - "array slices with non-trivial step " - "should have been disallowed during type inference") - - # One-dimensionally slicing an array only affects the outermost - # dimension. - shape = self.append(ir.GetAttr(value, "shape")) - lengths = [ - self.append(ir.GetAttr(shape, i)) - for i in range(len(shape.type.elts)) - ] - - # Compute outermost length – zero for "backwards" indices. - raw_len = self.append( - ir.Arith(ast.Sub(loc=None), mapped_stop_index, mapped_start_index)) - is_neg_len = self.append( - ir.Compare(ast.Lt(loc=None), raw_len, ir.Constant(0, raw_len.type))) - outer_len = self.append( - ir.Select(is_neg_len, ir.Constant(0, raw_len.type), raw_len)) - new_shape = self._make_array_shape([outer_len] + lengths[1:]) - - # Offset buffer pointer by start index (times stride for inner dims). - stride = reduce( - lambda l, r: self.append(ir.Arith(ast.Mult(loc=None), l, r)), - lengths[1:], ir.Constant(1, lengths[0].type)) - offset = self.append( - ir.Arith(ast.Mult(loc=None), stride, mapped_start_index)) - buffer = self.append(ir.GetAttr(value, "buffer")) - new_buffer = self.append(ir.Offset(buffer, offset)) - - return self.append(ir.Alloc([new_buffer, new_shape], node.type)) - else: - if node.slice.step is not None: - try: - old_assign, self.current_assign = self.current_assign, None - step = self.visit(node.slice.step) - finally: - self.current_assign = old_assign - - self._make_check( - self.append(ir.Compare(ast.NotEq(loc=None), step, ir.Constant(0, step.type))), - lambda: self.alloc_exn(builtins.TException("ValueError"), - ir.Constant("step cannot be zero", builtins.TStr())), - loc=node.slice.step.loc) - else: - step = ir.Constant(1, node.slice.type) - counting_up = self.append(ir.Compare(ast.Gt(loc=None), step, - ir.Constant(0, step.type))) - - unstepped_size = self.append(ir.Arith(ast.Sub(loc=None), - mapped_stop_index, mapped_start_index)) - slice_size_a = self.append(ir.Arith(ast.FloorDiv(loc=None), unstepped_size, step)) - slice_size_b = self.append(ir.Arith(ast.Mod(loc=None), unstepped_size, step)) - rem_not_empty = self.append(ir.Compare(ast.NotEq(loc=None), slice_size_b, - ir.Constant(0, slice_size_b.type))) - slice_size_c = self.append(ir.Arith(ast.Add(loc=None), slice_size_a, - ir.Constant(1, slice_size_a.type))) - slice_size = self.append(ir.Select(rem_not_empty, - slice_size_c, slice_size_a, - name="slice.size")) - self._make_check( - self.append(ir.Compare(ast.LtE(loc=None), slice_size, length)), - lambda slice_size, length: self.alloc_exn(builtins.TException("ValueError"), - ir.Constant("slice size {0} is larger than iterable length {1}", - builtins.TStr()), - slice_size, length), - params=[slice_size, length], - loc=node.slice.loc) - - if self.current_assign is None: - is_neg_size = self.append(ir.Compare(ast.Lt(loc=None), - slice_size, ir.Constant(0, slice_size.type))) - abs_slice_size = self.append(ir.Select(is_neg_size, - ir.Constant(0, slice_size.type), slice_size)) - other_value = self.append(ir.Alloc([abs_slice_size], value.type, - name="slice.result")) - else: - other_value = self.current_assign - - prehead = self.current_block - - head = self.current_block = self.add_block("slice.head") - prehead.append(ir.Branch(head)) - - index = self.append(ir.Phi(node.slice.type, - name="slice.index")) - index.add_incoming(mapped_start_index, prehead) - other_index = self.append(ir.Phi(node.slice.type, - name="slice.resindex")) - other_index.add_incoming(ir.Constant(0, node.slice.type), prehead) - - # Still within bounds? - bounded_up = self.append(ir.Compare(ast.Lt(loc=None), index, mapped_stop_index)) - bounded_down = self.append(ir.Compare(ast.Gt(loc=None), index, mapped_stop_index)) - within_bounds = self.append(ir.Select(counting_up, bounded_up, bounded_down)) - - body = self.current_block = self.add_block("slice.body") - - if self.current_assign is None: - elem = self.iterable_get(value, index) - self.append(ir.SetElem(other_value, other_index, elem)) - else: - elem = self.append(ir.GetElem(self.current_assign, other_index)) - self.append(ir.SetElem(value, index, elem)) - - next_index = self.append(ir.Arith(ast.Add(loc=None), index, step)) - index.add_incoming(next_index, body) - next_other_index = self.append(ir.Arith(ast.Add(loc=None), other_index, - ir.Constant(1, node.slice.type))) - other_index.add_incoming(next_other_index, body) - self.append(ir.Branch(head)) - - tail = self.current_block = self.add_block("slice.tail") - head.append(ir.BranchIf(within_bounds, body, tail)) - - if self.current_assign is None: - return other_value - - def visit_TupleT(self, node): - if self.current_assign is None: - return self.append(ir.Alloc([self.visit(elt) for elt in node.elts], node.type)) - else: - try: - old_assign = self.current_assign - for index, elt_node in enumerate(node.elts): - self.current_assign = \ - self.append(ir.GetAttr(old_assign, index, - name="{}.e{}".format(old_assign.name, index)), - loc=elt_node.loc) - self.visit(elt_node) - finally: - self.current_assign = old_assign - - def visit_ListT(self, node): - if self.current_assign is None: - elts = [self.visit(elt_node) for elt_node in node.elts] - lst = self.append(ir.Alloc([ir.Constant(len(node.elts), self._size_type)], - node.type)) - for index, elt_node in enumerate(elts): - self.append(ir.SetElem(lst, ir.Constant(index, self._size_type), elt_node)) - return lst - else: - length = self.iterable_len(self.current_assign) - self._make_check( - self.append(ir.Compare(ast.Eq(loc=None), length, - ir.Constant(len(node.elts), self._size_type))), - lambda length: self.alloc_exn(builtins.TException("ValueError"), - ir.Constant("list must be {0} elements long to decompose", builtins.TStr()), - length), - params=[length]) - - for index, elt_node in enumerate(node.elts): - elt = self.append(ir.GetElem(self.current_assign, - ir.Constant(index, self._size_type))) - try: - old_assign, self.current_assign = self.current_assign, elt - self.visit(elt_node) - finally: - self.current_assign = old_assign - - def visit_ListCompT(self, node): - assert len(node.generators) == 1 - comprehension = node.generators[0] - assert comprehension.ifs == [] - - iterable = self.visit(comprehension.iter) - length = self.iterable_len(iterable) - result = self.append(ir.Alloc([length], node.type)) - - try: - gen_suffix = ".gen@{}:{}".format(node.loc.line(), node.loc.column()) - env_type = ir.TEnvironment(name=self.current_function.name + gen_suffix, - vars=node.typing_env, outer=self.current_env.type) - env = self.append(ir.Alloc([], env_type, name="env.gen")) - old_env, self.current_env = self.current_env, env - - self.append(ir.SetLocal(env, "$outer", old_env)) - - def body_gen(index): - elt = self.iterable_get(iterable, index) - try: - old_assign, self.current_assign = self.current_assign, elt - self.visit(comprehension.target) - finally: - self.current_assign = old_assign - - mapped_elt = self.visit(node.elt) - self.append(ir.SetElem(result, index, mapped_elt)) - return self.append(ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, length.type))) - self._make_loop(ir.Constant(0, length.type), - lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, length)), - body_gen) - - return result - finally: - self.current_env = old_env - - def visit_BoolOpT(self, node): - blocks = [] - for value_node in node.values: - value_head = self.current_block - value = self.visit(value_node) - value_tail = self.current_block - - blocks.append((value, value_head, value_tail)) - self.current_block = self.add_block("boolop.seq") - - tail = self.current_block - phi = self.append(ir.Phi(node.type)) - for ((value, value_head, value_tail), (next_value_head, next_value_tail)) in \ - zip(blocks, [(h,t) for (v,h,t) in blocks[1:]] + [(tail, tail)]): - phi.add_incoming(value, value_tail) - if next_value_head != tail: - cond = self.coerce_to_bool(value, block=value_tail) - if isinstance(node.op, ast.And): - value_tail.append(ir.BranchIf(cond, next_value_head, tail)) - else: - value_tail.append(ir.BranchIf(cond, tail, next_value_head)) - else: - value_tail.append(ir.Branch(tail)) - return phi - - def _make_array_unaryop(self, name, make_op, result_type, arg_type): - try: - result = ir.Argument(result_type, "result") - arg = ir.Argument(arg_type, "arg") - - # TODO: We'd like to use a "C function" here to be able to supply - # specialised implementations in a library in the future (and e.g. avoid - # passing around the context argument), but the code generator currently - # doesn't allow emitting them. - args = [result, arg] - typ = types.TFunction(args=OrderedDict([(arg.name, arg.type) - for arg in args]), - optargs=OrderedDict(), - ret=builtins.TNone()) - env_args = [ir.EnvironmentArgument(self.current_env.type, "ARG.ENV")] - - old_loc, self.current_loc = self.current_loc, None - func = ir.Function(typ, name, env_args + args) - func.is_internal = True - func.is_generated = True - self.functions.append(func) - old_func, self.current_function = self.current_function, func - - entry = self.add_block("entry") - old_block, self.current_block = self.current_block, entry - - old_final_branch, self.final_branch = self.final_branch, None - old_unwind, self.unwind_target = self.unwind_target, None - - shape = self.append(ir.GetAttr(arg, "shape")) - - result_buffer = self.append(ir.GetAttr(result, "buffer")) - arg_buffer = self.append(ir.GetAttr(arg, "buffer")) - num_total_elts = self._get_total_array_len(shape) - - def body_gen(index): - a = self.append(ir.GetElem(arg_buffer, index)) - self.append( - ir.SetElem(result_buffer, index, make_op(a))) - return self.append( - ir.Arith(ast.Add(loc=None), index, ir.Constant(1, self._size_type))) - - self._make_loop( - ir.Constant(0, self._size_type), lambda index: self.append( - ir.Compare(ast.Lt(loc=None), index, num_total_elts)), body_gen) - - self.append(ir.Return(ir.Constant(None, builtins.TNone()))) - return func - finally: - self.current_loc = old_loc - self.current_function = old_func - self.current_block = old_block - self.final_branch = old_final_branch - self.unwind_target = old_unwind - - def _get_array_unaryop(self, name, make_op, result_type, arg_type): - name = "_array_{}_{}".format( - name, self._mangle_arrayop_types([result_type, arg_type])) - if name not in self.array_op_funcs: - self.array_op_funcs[name] = self._make_array_unaryop( - name, make_op, result_type, arg_type) - return self.array_op_funcs[name] - - def visit_UnaryOpT(self, node): - if isinstance(node.op, ast.Not): - cond = self.coerce_to_bool(self.visit(node.operand)) - return self.append(ir.Select(cond, - ir.Constant(False, builtins.TBool()), - ir.Constant(True, builtins.TBool()))) - elif isinstance(node.op, ast.Invert): - operand = self.visit(node.operand) - return self.append(ir.Arith(ast.BitXor(loc=None), - ir.Constant(-1, operand.type), operand)) - elif isinstance(node.op, ast.USub): - def make_sub(val): - return self.append(ir.Arith(ast.Sub(loc=None), - ir.Constant(0, val.type), val)) - operand = self.visit(node.operand) - if builtins.is_array(operand.type): - shape = self.append(ir.GetAttr(operand, "shape")) - result, _ = self._allocate_new_array(node.type.find()["elt"], shape) - func = self._get_array_unaryop("USub", make_sub, node.type, operand.type) - self._invoke_arrayop(func, [result, operand]) - return result - else: - return make_sub(operand) - elif isinstance(node.op, ast.UAdd): - # No-op. - return self.visit(node.operand) - else: - assert False - - def visit_CoerceT(self, node): - value = self.visit(node.value) - if node.type.find() == value.type: - return value - else: - if builtins.is_array(node.type): - result_elt = node.type.find()["elt"] - shape = self.append(ir.GetAttr(value, "shape")) - result, _ = self._allocate_new_array(result_elt, shape) - func = self._get_array_unaryop( - "Coerce", lambda v: self.append(ir.Coerce(v, result_elt)), - node.type, value.type) - self._invoke_arrayop(func, [result, value]) - return result - else: - return self.append( - ir.Coerce(value, - node.type, - name="{}.{}".format(_readable_name(value), - node.type.name))) - - def _get_total_array_len(self, shape): - lengths = [ - self.append(ir.GetAttr(shape, i)) for i in range(len(shape.type.elts)) - ] - return reduce(lambda l, r: self.append(ir.Arith(ast.Mult(loc=None), l, r)), - lengths[1:], lengths[0]) - - def _allocate_new_array(self, elt, shape): - total_length = self._get_total_array_len(shape) - buffer = self.append(ir.Alloc([total_length], types._TPointer(elt=elt))) - result_type = builtins.TArray(elt, types.TValue(len(shape.type.elts))) - return self.append(ir.Alloc([buffer, shape], result_type)), total_length - - def _make_array_binop(self, name, result_type, lhs_type, rhs_type, body_gen): - try: - result = ir.Argument(result_type, "result") - lhs = ir.Argument(lhs_type, "lhs") - rhs = ir.Argument(rhs_type, "rhs") - - # TODO: We'd like to use a "C function" here to be able to supply - # specialised implementations in a library in the future (and e.g. avoid - # passing around the context argument), but the code generator currently - # doesn't allow emitting them. - args = [result, lhs, rhs] - typ = types.TFunction(args=OrderedDict([(arg.name, arg.type) - for arg in args]), - optargs=OrderedDict(), - ret=builtins.TNone()) - env_args = [ir.EnvironmentArgument(self.current_env.type, "ARG.ENV")] - - old_loc, self.current_loc = self.current_loc, None - func = ir.Function(typ, name, env_args + args) - func.is_internal = True - func.is_generated = True - self.functions.append(func) - old_func, self.current_function = self.current_function, func - - entry = self.add_block("entry") - old_block, self.current_block = self.current_block, entry - - old_final_branch, self.final_branch = self.final_branch, None - old_unwind, self.unwind_target = self.unwind_target, None - - body_gen(result, lhs, rhs) - - self.append(ir.Return(ir.Constant(None, builtins.TNone()))) - return func - finally: - self.current_loc = old_loc - self.current_function = old_func - self.current_block = old_block - self.final_branch = old_final_branch - self.unwind_target = old_unwind - - def _make_array_elementwise_binop(self, name, result_type, lhs_type, - rhs_type, make_op): - def body_gen(result, lhs, rhs): - # At this point, shapes are assumed to match; could just pass buffer - # pointer for two of the three arrays as well. - result_buffer = self.append(ir.GetAttr(result, "buffer")) - shape = self.append(ir.GetAttr(result, "shape")) - num_total_elts = self._get_total_array_len(shape) - - if builtins.is_array(lhs.type): - lhs_buffer = self.append(ir.GetAttr(lhs, "buffer")) - def get_left(index): - return self.append(ir.GetElem(lhs_buffer, index)) - else: - def get_left(index): - return lhs - - if builtins.is_array(rhs.type): - rhs_buffer = self.append(ir.GetAttr(rhs, "buffer")) - def get_right(index): - return self.append(ir.GetElem(rhs_buffer, index)) - else: - def get_right(index): - return rhs - - def loop_gen(index): - l = get_left(index) - r = get_right(index) - result = make_op(l, r) - self.append(ir.SetElem(result_buffer, index, result)) - return self.append( - ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, self._size_type))) - - self._make_loop( - ir.Constant(0, self._size_type), lambda index: self.append( - ir.Compare(ast.Lt(loc=None), index, num_total_elts)), - loop_gen) - - return self._make_array_binop(name, result_type, lhs_type, rhs_type, - body_gen) - - def _mangle_arrayop_types(self, types): - def name_error(typ): - assert False, "Internal compiler error: No RPC tag for {}".format(typ) - - def mangle_name(typ): - typ = typ.find() - # rpc_tag is used to turn element types into mangled names for no - # particularly good reason apart from not having to invent yet another - # string representation. - if builtins.is_array(typ): - return mangle_name(typ["elt"]) + str(typ["num_dims"].find().value) - return ir.rpc_tag(typ, name_error).decode() - - return "_".join(mangle_name(t) for t in types) - - def _get_array_elementwise_binop(self, name, make_op, result_type, lhs_type, rhs_type): - # Currently, we always have any type coercions resolved explicitly in the AST. - # In the future, this might no longer be true and the three types might all - # differ. - name = "_array_{}_{}".format( - name, - self._mangle_arrayop_types([result_type, lhs_type, rhs_type])) - if name not in self.array_op_funcs: - self.array_op_funcs[name] = self._make_array_elementwise_binop( - name, result_type, lhs_type, rhs_type, make_op) - return self.array_op_funcs[name] - - def _invoke_arrayop(self, func, params): - closure = self.append( - ir.Closure(func, ir.Constant(None, ir.TEnvironment("arrayop", {})))) - if self.unwind_target is None: - self.append(ir.Call(closure, params, {})) - else: - after_invoke = self.add_block("arrayop.invoke") - self.append(ir.Invoke(func, params, {}, after_invoke, self.unwind_target)) - self.current_block = after_invoke - - def _get_array_offset(self, shape, indices): - result = indices[0] - for dim, index in zip(shape[1:], indices[1:]): - result = self.append(ir.Arith(ast.Mult(loc=None), result, dim)) - result = self.append(ir.Arith(ast.Add(loc=None), result, index)) - return result - - def _get_matmult(self, result_type, lhs_type, rhs_type): - name = "_array_MatMult_" + self._mangle_arrayop_types( - [result_type, lhs_type, rhs_type]) - if name not in self.array_op_funcs: - - def body_gen(result, lhs, rhs): - assert builtins.is_array(result.type), \ - "vec @ vec should have been normalised into array result" - - # We assume result has correct shape; could just pass buffer pointer - # as well. - result_buffer = self.append(ir.GetAttr(result, "buffer")) - lhs_buffer = self.append(ir.GetAttr(lhs, "buffer")) - rhs_buffer = self.append(ir.GetAttr(rhs, "buffer")) - - num_rows, num_summands, _, num_cols = self._get_matmult_shapes(lhs, rhs) - - elt = result.type["elt"].find() - env_type = ir.TEnvironment(name + ".loop", {"$total": elt}) - env = self.append(ir.Alloc([], env_type)) - - def row_loop(row_idx): - lhs_base_offset = self.append( - ir.Arith(ast.Mult(loc=None), row_idx, num_summands)) - lhs_base = self.append(ir.Offset(lhs_buffer, lhs_base_offset)) - result_base_offset = self.append( - ir.Arith(ast.Mult(loc=None), row_idx, num_cols)) - result_base = self.append( - ir.Offset(result_buffer, result_base_offset)) - - def col_loop(col_idx): - rhs_base = self.append(ir.Offset(rhs_buffer, col_idx)) - - self.append( - ir.SetLocal(env, "$total", ir.Constant(elt.zero(), elt))) - - def sum_loop(sum_idx): - lhs_elem = self.append(ir.GetElem(lhs_base, sum_idx)) - rhs_offset = self.append( - ir.Arith(ast.Mult(loc=None), sum_idx, num_cols)) - rhs_elem = self.append(ir.GetElem(rhs_base, rhs_offset)) - product = self.append( - ir.Arith(ast.Mult(loc=None), lhs_elem, rhs_elem)) - prev_total = self.append(ir.GetLocal(env, "$total")) - total = self.append( - ir.Arith(ast.Add(loc=None), prev_total, product)) - self.append(ir.SetLocal(env, "$total", total)) - return self.append( - ir.Arith(ast.Add(loc=None), sum_idx, - ir.Constant(1, self._size_type))) - - self._make_loop( - ir.Constant(0, self._size_type), lambda index: self.append( - ir.Compare(ast.Lt(loc=None), index, num_summands)), - sum_loop) - - total = self.append(ir.GetLocal(env, "$total")) - self.append(ir.SetElem(result_base, col_idx, total)) - - return self.append( - ir.Arith(ast.Add(loc=None), col_idx, - ir.Constant(1, self._size_type))) - - self._make_loop( - ir.Constant(0, self._size_type), lambda index: self.append( - ir.Compare(ast.Lt(loc=None), index, num_cols)), col_loop) - return self.append( - ir.Arith(ast.Add(loc=None), row_idx, - ir.Constant(1, self._size_type))) - - self._make_loop( - ir.Constant(0, self._size_type), lambda index: self.append( - ir.Compare(ast.Lt(loc=None), index, num_rows)), row_loop) - - self.array_op_funcs[name] = self._make_array_binop( - name, result_type, lhs_type, rhs_type, body_gen) - return self.array_op_funcs[name] - - def _get_matmult_shapes(self, lhs, rhs): - lhs_shape = self.append(ir.GetAttr(lhs, "shape")) - if lhs.type["num_dims"].value == 1: - lhs_shape_outer = ir.Constant(1, self._size_type) - lhs_shape_inner = self.append(ir.GetAttr(lhs_shape, 0)) - else: - lhs_shape_outer = self.append(ir.GetAttr(lhs_shape, 0)) - lhs_shape_inner = self.append(ir.GetAttr(lhs_shape, 1)) - - rhs_shape = self.append(ir.GetAttr(rhs, "shape")) - if rhs.type["num_dims"].value == 1: - rhs_shape_inner = self.append(ir.GetAttr(rhs_shape, 0)) - rhs_shape_outer = ir.Constant(1, self._size_type) - else: - rhs_shape_inner = self.append(ir.GetAttr(rhs_shape, 0)) - rhs_shape_outer = self.append(ir.GetAttr(rhs_shape, 1)) - - return lhs_shape_outer, lhs_shape_inner, rhs_shape_inner, rhs_shape_outer - - def _make_array_shape(self, dims): - return self.append(ir.Alloc(dims, types.TTuple([self._size_type] * len(dims)))) - - def _emit_matmult(self, node, left, right): - # TODO: Also expose as numpy.dot. - lhs = self.visit(left) - rhs = self.visit(right) - - num_rows, lhs_inner, rhs_inner, num_cols = self._get_matmult_shapes(lhs, rhs) - self._make_check( - self.append(ir.Compare(ast.Eq(loc=None), lhs_inner, rhs_inner)), - lambda lhs_inner, rhs_inner: self.alloc_exn( - builtins.TException("ValueError"), - ir.Constant( - "inner dimensions for matrix multiplication do not match ({0} vs. {1})", - builtins.TStr()), lhs_inner, rhs_inner), - params=[lhs_inner, rhs_inner], - loc=node.loc) - result_shape = self._make_array_shape([num_rows, num_cols]) - - final_type = node.type.find() - if not builtins.is_array(final_type): - elt = node.type - result_dims = 0 - else: - elt = final_type["elt"] - result_dims = final_type["num_dims"].value - - result, _ = self._allocate_new_array(elt, result_shape) - func = self._get_matmult(result.type, left.type, right.type) - self._invoke_arrayop(func, [result, lhs, rhs]) - - if result_dims == 2: - return result - result_buffer = self.append(ir.GetAttr(result, "buffer")) - if result_dims == 1: - shape = self._make_array_shape( - [num_cols if lhs.type["num_dims"].value == 1 else num_rows]) - return self.append(ir.Alloc([result_buffer, shape], node.type)) - return self.append(ir.GetElem(result_buffer, ir.Constant(0, self._size_type))) - - def _broadcast_binop(self, name, make_op, result_type, lhs, rhs, assign_to_lhs): - # Broadcast scalars (broadcasting higher dimensions is not yet allowed in the - # language). - broadcast = False - array_arg = lhs - if not builtins.is_array(lhs.type): - broadcast = True - array_arg = rhs - elif not builtins.is_array(rhs.type): - broadcast = True - - shape = self.append(ir.GetAttr(array_arg, "shape")) - - if not broadcast: - rhs_shape = self.append(ir.GetAttr(rhs, "shape")) - self._make_check( - self.append(ir.Compare(ast.Eq(loc=None), shape, rhs_shape)), - lambda: self.alloc_exn( - builtins.TException("ValueError"), - ir.Constant("operands could not be broadcast together", - builtins.TStr()))) - if assign_to_lhs: - result = lhs - else: - elt = result_type.find()["elt"] - result, _ = self._allocate_new_array(elt, shape) - func = self._get_array_elementwise_binop(name, make_op, result_type, lhs.type, - rhs.type) - self._invoke_arrayop(func, [result, lhs, rhs]) - return result - - def visit_BinOpT(self, node): - if isinstance(node.op, ast.MatMult): - return self._emit_matmult(node, node.left, node.right) - elif builtins.is_array(node.type): - lhs = self.visit(node.left) - rhs = self.visit(node.right) - name = type(node.op).__name__ - def make_op(l, r): - return self.append(ir.Arith(node.op, l, r)) - return self._broadcast_binop(name, make_op, node.type, lhs, rhs, - assign_to_lhs=False) - elif builtins.is_numeric(node.type): - lhs = self.visit(node.left) - rhs = self.visit(node.right) - if isinstance(node.op, (ast.LShift, ast.RShift)): - # Check for negative shift amount. - self._make_check( - self.append(ir.Compare(ast.GtE(loc=None), rhs, ir.Constant(0, rhs.type))), - lambda: self.alloc_exn(builtins.TException("ValueError"), - ir.Constant("shift amount must be nonnegative", builtins.TStr())), - loc=node.right.loc) - elif isinstance(node.op, (ast.Div, ast.FloorDiv, ast.Mod)): - self._make_check( - self.append(ir.Compare(ast.NotEq(loc=None), rhs, ir.Constant(0, rhs.type))), - lambda: self.alloc_exn(builtins.TException("ZeroDivisionError"), - ir.Constant("cannot divide by zero", builtins.TStr())), - loc=node.right.loc) - - return self.append(ir.Arith(node.op, lhs, rhs)) - elif isinstance(node.op, ast.Add): # list + list, tuple + tuple, str + str - lhs, rhs = self.visit(node.left), self.visit(node.right) - if types.is_tuple(node.left.type) and types.is_tuple(node.right.type): - elts = [] - for index, elt in enumerate(node.left.type.elts): - elts.append(self.append(ir.GetAttr(lhs, index))) - for index, elt in enumerate(node.right.type.elts): - elts.append(self.append(ir.GetAttr(rhs, index))) - return self.append(ir.Alloc(elts, node.type)) - elif builtins.is_listish(node.left.type) and builtins.is_listish(node.right.type): - lhs_length = self.iterable_len(lhs) - rhs_length = self.iterable_len(rhs) - - result_length = self.append(ir.Arith(ast.Add(loc=None), lhs_length, rhs_length)) - result = self.append(ir.Alloc([result_length], node.type)) - - # Copy lhs - def body_gen(index): - elt = self.append(ir.GetElem(lhs, index)) - self.append(ir.SetElem(result, index, elt)) - return self.append(ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, self._size_type))) - self._make_loop(ir.Constant(0, self._size_type), - lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, lhs_length)), - body_gen) - - # Copy rhs - def body_gen(index): - elt = self.append(ir.GetElem(rhs, index)) - result_index = self.append(ir.Arith(ast.Add(loc=None), index, lhs_length)) - self.append(ir.SetElem(result, result_index, elt)) - return self.append(ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, self._size_type))) - self._make_loop(ir.Constant(0, self._size_type), - lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, rhs_length)), - body_gen) - - return result - else: - assert False - elif isinstance(node.op, ast.Mult): # list * int, int * list - lhs, rhs = self.visit(node.left), self.visit(node.right) - if builtins.is_listish(lhs.type) and builtins.is_int(rhs.type): - lst, num = lhs, rhs - elif builtins.is_int(lhs.type) and builtins.is_listish(rhs.type): - lst, num = rhs, lhs - else: - assert False - - lst_length = self.iterable_len(lst) - - result_length = self.append(ir.Arith(ast.Mult(loc=None), lst_length, num)) - result = self.append(ir.Alloc([result_length], node.type)) - - # num times... - def body_gen(num_index): - # ... copy the list - def body_gen(lst_index): - elt = self.append(ir.GetElem(lst, lst_index)) - base_index = self.append(ir.Arith(ast.Mult(loc=None), - num_index, lst_length)) - result_index = self.append(ir.Arith(ast.Add(loc=None), - base_index, lst_index)) - self.append(ir.SetElem(result, base_index, elt)) - return self.append(ir.Arith(ast.Add(loc=None), lst_index, - ir.Constant(1, self._size_type))) - self._make_loop(ir.Constant(0, self._size_type), - lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, lst_length)), - body_gen) - - return self.append(ir.Arith(ast.Add(loc=None), num_index, - ir.Constant(1, self._size_type))) - self._make_loop(ir.Constant(0, self._size_type), - lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, num)), - body_gen) - - return result - else: - assert False - - def polymorphic_compare_pair_order(self, op, lhs, rhs): - if builtins.is_none(lhs.type) and builtins.is_none(rhs.type): - return self.append(ir.Compare(op, lhs, rhs)) - elif builtins.is_numeric(lhs.type) and builtins.is_numeric(rhs.type): - return self.append(ir.Compare(op, lhs, rhs)) - elif builtins.is_bool(lhs.type) and builtins.is_bool(rhs.type): - return self.append(ir.Compare(op, lhs, rhs)) - elif types.is_tuple(lhs.type) and types.is_tuple(rhs.type): - result = None - for index in range(len(lhs.type.elts)): - lhs_elt = self.append(ir.GetAttr(lhs, index)) - rhs_elt = self.append(ir.GetAttr(rhs, index)) - elt_result = self.polymorphic_compare_pair(op, lhs_elt, rhs_elt) - if result is None: - result = elt_result - else: - result = self.append(ir.Select(result, elt_result, - ir.Constant(False, builtins.TBool()))) - return result - elif builtins.is_listish(lhs.type) and builtins.is_listish(rhs.type): - head = self.current_block - lhs_length = self.iterable_len(lhs) - rhs_length = self.iterable_len(rhs) - compare_length = self.append(ir.Compare(op, lhs_length, rhs_length)) - eq_length = self.append(ir.Compare(ast.Eq(loc=None), lhs_length, rhs_length)) - - # If the length is the same, compare element-by-element - # and break when the comparison result is false - loop_head = self.add_block("compare.head") - self.current_block = loop_head - index_phi = self.append(ir.Phi(self._size_type)) - index_phi.add_incoming(ir.Constant(0, self._size_type), head) - loop_cond = self.append(ir.Compare(ast.Lt(loc=None), index_phi, lhs_length)) - - loop_body = self.add_block("compare.body") - self.current_block = loop_body - lhs_elt = self.append(ir.GetElem(lhs, index_phi)) - rhs_elt = self.append(ir.GetElem(rhs, index_phi)) - body_result = self.polymorphic_compare_pair(op, lhs_elt, rhs_elt) - body_end = self.current_block - - loop_body2 = self.add_block("compare.body2") - self.current_block = loop_body2 - index_next = self.append(ir.Arith(ast.Add(loc=None), index_phi, - ir.Constant(1, self._size_type))) - self.append(ir.Branch(loop_head)) - index_phi.add_incoming(index_next, loop_body2) - - tail = self.add_block("compare.tail") - self.current_block = tail - phi = self.append(ir.Phi(builtins.TBool())) - head.append(ir.BranchIf(eq_length, loop_head, tail)) - phi.add_incoming(compare_length, head) - loop_head.append(ir.BranchIf(loop_cond, loop_body, tail)) - phi.add_incoming(ir.Constant(True, builtins.TBool()), loop_head) - body_end.append(ir.BranchIf(body_result, loop_body2, tail)) - phi.add_incoming(body_result, body_end) - - if isinstance(op, ast.NotEq): - result = self.append(ir.Select(phi, - ir.Constant(False, builtins.TBool()), ir.Constant(True, builtins.TBool()))) - else: - result = phi - - return result - else: - loc = lhs.loc - loc.end = rhs.loc.end - diag = diagnostic.Diagnostic("error", - "Custom object comparison is not supported", - {}, - loc) - self.engine.process(diag) - - def polymorphic_compare_pair_inclusion(self, needle, haystack): - if builtins.is_range(haystack.type): - # Optimized range `in` operator - start = self.append(ir.GetAttr(haystack, "start")) - stop = self.append(ir.GetAttr(haystack, "stop")) - step = self.append(ir.GetAttr(haystack, "step")) - after_start = self.append(ir.Compare(ast.GtE(loc=None), needle, start)) - after_stop = self.append(ir.Compare(ast.Lt(loc=None), needle, stop)) - from_start = self.append(ir.Arith(ast.Sub(loc=None), needle, start)) - mod_step = self.append(ir.Arith(ast.Mod(loc=None), from_start, step)) - on_step = self.append(ir.Compare(ast.Eq(loc=None), mod_step, - ir.Constant(0, mod_step.type))) - result = self.append(ir.Select(after_start, after_stop, - ir.Constant(False, builtins.TBool()))) - result = self.append(ir.Select(result, on_step, - ir.Constant(False, builtins.TBool()))) - elif builtins.is_iterable(haystack.type): - length = self.iterable_len(haystack) - - cmp_result = loop_body2 = None - def body_gen(index): - nonlocal cmp_result, loop_body2 - - elt = self.iterable_get(haystack, index) - cmp_result = self.polymorphic_compare_pair(ast.Eq(loc=None), needle, elt) - - loop_body2 = self.add_block("compare.body") - self.current_block = loop_body2 - return self.append(ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, length.type))) - loop_head, loop_body, loop_tail = \ - self._make_loop(ir.Constant(0, length.type), - lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, length)), - body_gen, name="compare") - - loop_body.append(ir.BranchIf(cmp_result, loop_tail, loop_body2)) - phi = loop_tail.prepend(ir.Phi(builtins.TBool())) - phi.add_incoming(ir.Constant(False, builtins.TBool()), loop_head) - phi.add_incoming(ir.Constant(True, builtins.TBool()), loop_body) - - result = phi - else: - loc = needle.loc - loc.end = haystack.loc.end - diag = diagnostic.Diagnostic("error", - "Custom object inclusion test is not supported", - {}, - loc) - self.engine.process(diag) - - return result - - def invert(self, value): - return self.append(ir.Select(value, - ir.Constant(False, builtins.TBool()), - ir.Constant(True, builtins.TBool()))) - - def polymorphic_compare_pair(self, op, lhs, rhs): - if isinstance(op, (ast.Is, ast.IsNot)): - # The backend will handle equality of aggregates. - return self.append(ir.Compare(op, lhs, rhs)) - elif isinstance(op, ast.In): - return self.polymorphic_compare_pair_inclusion(lhs, rhs) - elif isinstance(op, ast.NotIn): - result = self.polymorphic_compare_pair_inclusion(lhs, rhs) - return self.invert(result) - elif isinstance(op, (ast.Eq, ast.Lt, ast.LtE, ast.Gt, ast.GtE)): - return self.polymorphic_compare_pair_order(op, lhs, rhs) - elif isinstance(op, ast.NotEq): - result = self.polymorphic_compare_pair_order(ast.Eq(loc=op.loc), lhs, rhs) - return self.invert(result) - else: - assert False - - def visit_CompareT(self, node): - # Essentially a sequence of `and`s performed over results - # of comparisons. - blocks = [] - lhs = self.visit(node.left) - for op, rhs_node in zip(node.ops, node.comparators): - result_head = self.current_block - rhs = self.visit(rhs_node) - result = self.polymorphic_compare_pair(op, lhs, rhs) - result_tail = self.current_block - - blocks.append((result, result_head, result_tail)) - self.current_block = self.add_block("compare.seq") - lhs = rhs - - tail = self.current_block - phi = self.append(ir.Phi(node.type)) - for ((result, result_head, result_tail), (next_result_head, next_result_tail)) in \ - zip(blocks, [(h,t) for (v,h,t) in blocks[1:]] + [(tail, tail)]): - phi.add_incoming(result, result_tail) - if next_result_head != tail: - result_tail.append(ir.BranchIf(result, next_result_head, tail)) - else: - result_tail.append(ir.Branch(tail)) - return phi - - # Keep this function with builtins.TException.attributes. - def alloc_exn(self, typ, message=None, param0=None, param1=None, param2=None): - typ = typ.find() - name = "{}:{}".format(typ.id, typ.name) - attributes = [ - ir.Constant(name, builtins.TStr()), # typeinfo - ir.Constant("", builtins.TStr()), # file - ir.Constant(0, builtins.TInt32()), # line - ir.Constant(0, builtins.TInt32()), # column - ir.Constant("", builtins.TStr()), # function - ] - - if message is None: - attributes.append(ir.Constant(typ.name, builtins.TStr())) - else: - attributes.append(message) # message - - param_type = builtins.TInt64() - for param in [param0, param1, param2]: - if param is None: - attributes.append(ir.Constant(0, builtins.TInt64())) - else: - if param.type != param_type: - param = self.append(ir.Coerce(param, param_type)) - attributes.append(param) # paramN, N=0:2 - - return self.append(ir.Alloc(attributes, typ)) - - def visit_builtin_call(self, node): - # A builtin by any other name... Ignore node.func, just use the type. - typ = node.func.type - if types.is_builtin(typ, "bool"): - if len(node.args) == 0 and len(node.keywords) == 0: - return ir.Constant(False, builtins.TBool()) - elif len(node.args) == 1 and len(node.keywords) == 0: - arg = self.visit(node.args[0]) - return self.coerce_to_bool(arg) - else: - assert False - elif types.is_builtin(typ, "int") or \ - types.is_builtin(typ, "int32") or types.is_builtin(typ, "int64"): - if len(node.args) == 0 and len(node.keywords) == 0: - return ir.Constant(0, node.type) - elif len(node.args) == 1 and \ - (len(node.keywords) == 0 or \ - len(node.keywords) == 1 and node.keywords[0].arg == 'width'): - # The width argument is purely type-level - arg = self.visit(node.args[0]) - return self.append(ir.Coerce(arg, node.type)) - else: - assert False - elif types.is_builtin(typ, "float"): - if len(node.args) == 0 and len(node.keywords) == 0: - return ir.Constant(0.0, builtins.TFloat()) - elif len(node.args) == 1 and len(node.keywords) == 0: - arg = self.visit(node.args[0]) - return self.append(ir.Coerce(arg, node.type)) - else: - assert False - elif (types.is_builtin(typ, "list") or - types.is_builtin(typ, "bytearray") or types.is_builtin(typ, "bytes")): - if len(node.args) == 0 and len(node.keywords) == 0: - length = ir.Constant(0, builtins.TInt32()) - return self.append(ir.Alloc([length], node.type)) - elif len(node.args) == 1 and len(node.keywords) == 0: - arg = self.visit(node.args[0]) - length = self.iterable_len(arg) - result = self.append(ir.Alloc([length], node.type)) - - def body_gen(index): - elt = self.iterable_get(arg, index) - elt = self.append(ir.Coerce(elt, builtins.get_iterable_elt(node.type))) - self.append(ir.SetElem(result, index, elt)) - return self.append(ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, length.type))) - self._make_loop(ir.Constant(0, length.type), - lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, length)), - body_gen) - - return result - else: - assert False - elif types.is_builtin(typ, "array"): - if len(node.args) == 1 and len(node.keywords) in (0, 1): - result_type = node.type.find() - arg = self.visit(node.args[0]) - - result_elt = result_type["elt"].find() - num_dims = result_type["num_dims"].value - - # Derive shape from first element on each level (and fail later if the - # array is in fact jagged). - first_elt = None - lengths = [] - for dim_idx in range(num_dims): - if first_elt is None: - first_elt = arg - else: - first_elt = self.iterable_get(first_elt, - ir.Constant(0, self._size_type)) - lengths.append(self.iterable_len(first_elt)) - - shape = self.append(ir.Alloc(lengths, result_type.attributes["shape"])) - num_total_elts = self._get_total_array_len(shape) - - # Assign buffer from nested iterables. - buffer = self.append( - ir.Alloc([num_total_elts], result_type.attributes["buffer"])) - - def assign_elems(outer_indices, indexed_arg): - if len(outer_indices) == num_dims: - dest_idx = self._get_array_offset(lengths, outer_indices) - coerced = self.append(ir.Coerce(indexed_arg, result_elt)) - self.append(ir.SetElem(buffer, dest_idx, coerced)) - else: - this_level_len = self.iterable_len(indexed_arg) - dim_idx = len(outer_indices) - if dim_idx > 0: - # Check for rectangularity (outermost index is never jagged, - # by definition). - result_len = self.append(ir.GetAttr(shape, dim_idx)) - self._make_check( - self.append(ir.Compare(ast.Eq(loc=None), this_level_len, result_len)), - lambda a, b: self.alloc_exn( - builtins.TException("ValueError"), - ir.Constant( - "arrays must be rectangular (lengths were {0} vs. {1})", - builtins.TStr()), a, b), - params=[this_level_len, result_len], - loc=node.loc) - - def body_gen(index): - elem = self.iterable_get(indexed_arg, index) - assign_elems(outer_indices + [index], elem) - return self.append( - ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, self._size_type))) - self._make_loop( - ir.Constant(0, self._size_type), lambda index: self.append( - ir.Compare(ast.Lt(loc=None), index, this_level_len)), body_gen) - assign_elems([], arg) - return self.append(ir.Alloc([buffer, shape], node.type)) - else: - assert False - elif types.is_builtin(typ, "range"): - elt_typ = builtins.get_iterable_elt(node.type) - if len(node.args) == 1 and len(node.keywords) == 0: - max_arg = self.visit(node.args[0]) - return self.append(ir.Alloc([ - ir.Constant(elt_typ.zero(), elt_typ), - max_arg, - ir.Constant(elt_typ.one(), elt_typ), - ], node.type)) - elif len(node.args) == 2 and len(node.keywords) == 0: - min_arg = self.visit(node.args[0]) - max_arg = self.visit(node.args[1]) - return self.append(ir.Alloc([ - min_arg, - max_arg, - ir.Constant(elt_typ.one(), elt_typ), - ], node.type)) - elif len(node.args) == 3 and len(node.keywords) == 0: - min_arg = self.visit(node.args[0]) - max_arg = self.visit(node.args[1]) - step_arg = self.visit(node.args[2]) - return self.append(ir.Alloc([ - min_arg, - max_arg, - step_arg, - ], node.type)) - else: - assert False - elif types.is_builtin(typ, "len"): - if len(node.args) == 1 and len(node.keywords) == 0: - arg = self.visit(node.args[0]) - return self.iterable_len(arg) - else: - assert False - elif types.is_builtin(typ, "round"): - if len(node.args) == 1 and len(node.keywords) == 0: - arg = self.visit(node.args[0]) - return self.append(ir.Builtin("round", [arg], node.type)) - else: - assert False - elif types.is_builtin(typ, "abs"): - if len(node.args) == 1 and len(node.keywords) == 0: - arg = self.visit(node.args[0]) - neg = self.append( - ir.Arith(ast.Sub(loc=None), ir.Constant(0, arg.type), arg)) - cond = self.append( - ir.Compare(ast.Lt(loc=None), arg, ir.Constant(0, arg.type))) - return self.append(ir.Select(cond, neg, arg)) - else: - assert False - elif types.is_builtin(typ, "min"): - if len(node.args) == 2 and len(node.keywords) == 0: - arg0, arg1 = map(self.visit, node.args) - cond = self.append(ir.Compare(ast.Lt(loc=None), arg0, arg1)) - return self.append(ir.Select(cond, arg0, arg1)) - else: - assert False - elif types.is_builtin(typ, "max"): - if len(node.args) == 2 and len(node.keywords) == 0: - arg0, arg1 = map(self.visit, node.args) - cond = self.append(ir.Compare(ast.Gt(loc=None), arg0, arg1)) - return self.append(ir.Select(cond, arg0, arg1)) - else: - assert False - elif types.is_builtin(typ, "make_array"): - if len(node.args) == 2 and len(node.keywords) == 0: - arg0, arg1 = map(self.visit, node.args) - - num_dims = node.type.find()["num_dims"].value - if types.is_tuple(arg0.type): - lens = [self.append(ir.GetAttr(arg0, i)) for i in range(num_dims)] - else: - assert num_dims == 1 - lens = [arg0] - - shape = self._make_array_shape(lens) - result, total_len = self._allocate_new_array(node.type.find()["elt"], - shape) - - def body_gen(index): - self.append(ir.SetElem(result, index, arg1)) - return self.append( - ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, self._size_type))) - - self._make_loop( - ir.Constant(0, self._size_type), lambda index: self.append( - ir.Compare(ast.Lt(loc=None), index, total_len)), body_gen) - return result - else: - assert False - elif types.is_builtin(typ, "numpy.transpose"): - if len(node.args) == 1 and len(node.keywords) == 0: - arg, = map(self.visit, node.args) - - num_dims = arg.type.find()["num_dims"].value - if num_dims == 1: - # No-op as per NumPy semantics. - return arg - assert num_dims == 2 - arg_shape = self.append(ir.GetAttr(arg, "shape")) - dim0 = self.append(ir.GetAttr(arg_shape, 0)) - dim1 = self.append(ir.GetAttr(arg_shape, 1)) - shape = self._make_array_shape([dim1, dim0]) - result, _ = self._allocate_new_array(node.type.find()["elt"], shape) - arg_buffer = self.append(ir.GetAttr(arg, "buffer")) - result_buffer = self.append(ir.GetAttr(result, "buffer")) - - def outer_gen(idx1): - arg_base = self.append(ir.Offset(arg_buffer, idx1)) - result_offset = self.append(ir.Arith(ast.Mult(loc=None), idx1, - dim0)) - result_base = self.append(ir.Offset(result_buffer, result_offset)) - - def inner_gen(idx0): - arg_offset = self.append( - ir.Arith(ast.Mult(loc=None), idx0, dim1)) - val = self.append(ir.GetElem(arg_base, arg_offset)) - self.append(ir.SetElem(result_base, idx0, val)) - return self.append( - ir.Arith(ast.Add(loc=None), idx0, ir.Constant(1, - idx0.type))) - - self._make_loop( - ir.Constant(0, self._size_type), lambda idx0: self.append( - ir.Compare(ast.Lt(loc=None), idx0, dim0)), inner_gen) - return self.append( - ir.Arith(ast.Add(loc=None), idx1, ir.Constant(1, idx1.type))) - - self._make_loop( - ir.Constant(0, self._size_type), - lambda idx1: self.append(ir.Compare(ast.Lt(loc=None), idx1, dim1)), - outer_gen) - return result - else: - assert False - elif types.is_builtin(typ, "print"): - self.polymorphic_print([self.visit(arg) for arg in node.args], - separator=" ", suffix="\n") - return ir.Constant(None, builtins.TNone()) - elif types.is_builtin(typ, "rtio_log"): - prefix, *args = node.args - self.polymorphic_print([self.visit(prefix)], - separator=" ", suffix="\x1E", as_rtio=True) - self.polymorphic_print([self.visit(arg) for arg in args], - separator=" ", suffix="\x1D", as_rtio=True) - return ir.Constant(None, builtins.TNone()) - elif types.is_builtin(typ, "delay"): - if len(node.args) == 1 and len(node.keywords) == 0: - arg = self.visit(node.args[0]) - arg_mu_float = self.append(ir.Arith(ast.Div(loc=None), arg, self.ref_period)) - arg_mu = self.append(ir.Builtin("round", [arg_mu_float], builtins.TInt64())) - return self.append(ir.Builtin("delay_mu", [arg_mu], builtins.TNone())) - else: - assert False - elif types.is_builtin(typ, "now_mu") or types.is_builtin(typ, "delay_mu") \ - or types.is_builtin(typ, "at_mu"): - return self.append(ir.Builtin(typ.name, - [self.visit(arg) for arg in node.args], node.type)) - elif types.is_exn_constructor(typ): - return self.alloc_exn(node.type, *[self.visit(arg_node) for arg_node in node.args]) - elif types.is_constructor(typ): - return self.append(ir.Alloc([], typ.instance)) - else: - diag = diagnostic.Diagnostic("error", - "builtin function '{name}' cannot be used in this context", - {"name": typ.find().name}, - node.loc) - self.engine.process(diag) - - def _user_call(self, callee, positional, keywords, arg_exprs={}): - if types.is_function(callee.type) or types.is_rpc(callee.type): - func = callee - self_arg = None - fn_typ = callee.type - offset = 0 - elif types.is_method(callee.type): - func = self.append(ir.GetAttr(callee, "__func__", - name="{}.ENV".format(callee.name))) - self_arg = self.append(ir.GetAttr(callee, "__self__", - name="{}.SLF".format(callee.name))) - fn_typ = types.get_method_function(callee.type) - offset = 1 - else: - assert False - - if types.is_rpc(fn_typ): - if self_arg is None: - args = positional - else: - args = [self_arg] + positional - - for keyword in keywords: - arg = keywords[keyword] - args.append(self.append(ir.Alloc([ir.Constant(keyword, builtins.TStr()), arg], - ir.TKeyword(arg.type)))) - else: - args = [None] * (len(fn_typ.args) + len(fn_typ.optargs)) - - for index, arg in enumerate(positional): - if index + offset < len(fn_typ.args): - args[index + offset] = arg - else: - args[index + offset] = self.append(ir.Alloc([arg], ir.TOption(arg.type))) - - for keyword in keywords: - arg = keywords[keyword] - if keyword in fn_typ.args: - for index, arg_name in enumerate(fn_typ.args): - if keyword == arg_name: - assert args[index] is None - args[index] = arg - break - elif keyword in fn_typ.optargs: - for index, optarg_name in enumerate(fn_typ.optargs): - if keyword == optarg_name: - assert args[len(fn_typ.args) + index] is None - args[len(fn_typ.args) + index] = \ - self.append(ir.Alloc([arg], ir.TOption(arg.type))) - break - - for index, optarg_name in enumerate(fn_typ.optargs): - if args[len(fn_typ.args) + index] is None: - args[len(fn_typ.args) + index] = \ - self.append(ir.Alloc([], ir.TOption(fn_typ.optargs[optarg_name]))) - - if self_arg is not None: - assert args[0] is None - args[0] = self_arg - - assert None not in args - - if self.unwind_target is None or \ - types.is_external_function(callee.type) and "nounwind" in callee.type.flags: - insn = self.append(ir.Call(func, args, arg_exprs)) - else: - after_invoke = self.add_block("invoke") - insn = self.append(ir.Invoke(func, args, arg_exprs, - after_invoke, self.unwind_target)) - self.current_block = after_invoke - - return insn - - def visit_CallT(self, node): - if not types.is_builtin(node.func.type): - callee = self.visit(node.func) - args = [self.visit(arg_node) for arg_node in node.args] - keywords = {kw_node.arg: self.visit(kw_node.value) for kw_node in node.keywords} - - if node.iodelay is not None and not iodelay.is_const(node.iodelay, 0): - before_delay = self.current_block - during_delay = self.add_block("delay.head") - before_delay.append(ir.Branch(during_delay)) - self.current_block = during_delay - - if types.is_builtin(node.func.type): - insn = self.visit_builtin_call(node) - elif (types.is_broadcast_across_arrays(node.func.type) and len(args) >= 1 - and any(builtins.is_array(arg.type) for arg in args)): - # The iodelay machinery set up in the surrounding code was - # deprecated/a relic from the past when array broadcasting support - # was added, so no attempt to keep the delay tracking intact is - # made. - def make_call(*args): - return self._user_call(ir.Constant(None, callee.type), args, {}, - node.arg_exprs) - # TODO: Generate more generically if non-externals are allowed. - name = node.func.type.find().name - - if len(args) == 1: - shape = self.append(ir.GetAttr(args[0], "shape")) - result, _ = self._allocate_new_array(node.type.find()["elt"], shape) - func = self._get_array_unaryop(name, make_call, node.type, args[0].type) - self._invoke_arrayop(func, [result, args[0]]) - insn = result - elif len(args) == 2: - insn = self._broadcast_binop(name, make_call, node.type, *args, - assign_to_lhs=False) - else: - assert False, "Broadcasting for {} arguments not implemented".format(len) - else: - insn = self._user_call(callee, args, keywords, node.arg_exprs) - if isinstance(node.func, asttyped.AttributeT): - attr_node = node.func - self.method_map[(attr_node.value.type.find(), - attr_node.attr)].append(insn) - - if node.iodelay is not None and not iodelay.is_const(node.iodelay, 0): - after_delay = self.add_block("delay.tail") - self.append(ir.Delay(node.iodelay, insn, after_delay)) - self.current_block = after_delay - - return insn - - def visit_QuoteT(self, node): - return self.append(ir.Quote(node.value, node.type)) - - def _get_raise_assert_func(self): - """Emit the helper function that constructs AssertionErrors and raises - them, if it does not already exist in the current module. - - A separate function is used for code size reasons. (This could also be - compiled into a stand-alone support library instead.) - """ - if self.raise_assert_func: - return self.raise_assert_func - try: - msg = ir.Argument(builtins.TStr(), "msg") - file = ir.Argument(builtins.TStr(), "file") - line = ir.Argument(builtins.TInt32(), "line") - col = ir.Argument(builtins.TInt32(), "col") - function = ir.Argument(builtins.TStr(), "function") - - args = [msg, file, line, col, function] - typ = types.TFunction(args=OrderedDict([(arg.name, arg.type) - for arg in args]), - optargs=OrderedDict(), - ret=builtins.TNone()) - env = ir.TEnvironment(name="raise", vars={}) - env_arg = ir.EnvironmentArgument(env, "ARG.ENV") - func = ir.Function(typ, "_artiq_raise_assert", [env_arg] + args) - func.is_internal = True - func.is_cold = True - func.is_generated = True - self.functions.append(func) - old_func, self.current_function = self.current_function, func - - entry = self.add_block("entry") - old_block, self.current_block = self.current_block, entry - old_final_branch, self.final_branch = self.final_branch, None - old_unwind, self.unwind_target = self.unwind_target, None - - exn = self.alloc_exn(builtins.TException("AssertionError"), message=msg) - self.append(ir.SetAttr(exn, "__file__", file)) - self.append(ir.SetAttr(exn, "__line__", line)) - self.append(ir.SetAttr(exn, "__col__", col)) - self.append(ir.SetAttr(exn, "__func__", function)) - self.append(ir.Raise(exn)) - finally: - self.current_function = old_func - self.current_block = old_block - self.final_branch = old_final_branch - self.unwind_target = old_unwind - - self.raise_assert_func = func - return self.raise_assert_func - - def visit_Assert(self, node): - cond = self.visit(node.test) - head = self.current_block - - if_failed = self.current_block = self.add_block("assert.fail") - text = str(node.msg.s) if node.msg else "AssertionError" - msg = ir.Constant(text, builtins.TStr()) - loc_file = ir.Constant(node.loc.source_buffer.name, builtins.TStr()) - loc_line = ir.Constant(node.loc.line(), builtins.TInt32()) - loc_column = ir.Constant(node.loc.column(), builtins.TInt32()) - loc_function = ir.Constant(".".join(self.name), builtins.TStr()) - self._invoke_raising_func(self._get_raise_assert_func(), [ - msg, loc_file, loc_line, loc_column, loc_function - ], "assert.fail") - - tail = self.current_block = self.add_block("assert.tail") - self.append(ir.BranchIf(cond, tail, if_failed), block=head) - - def polymorphic_print(self, values, separator, suffix="", as_repr=False, as_rtio=False): - def printf(format_string, *args): - format = ir.Constant(format_string, builtins.TStr()) - if as_rtio: - self.append(ir.Builtin("rtio_log", [format, *args], builtins.TNone())) - else: - self.append(ir.Builtin("printf", [format, *args], builtins.TNone())) - - format_string = "" - args = [] - def flush(): - nonlocal format_string, args - if format_string != "": - printf(format_string + "\x00", *args) - format_string = "" - args = [] - - for value in values: - if format_string != "": - format_string += separator - - if types.is_tuple(value.type): - format_string += "("; flush() - self.polymorphic_print([self.append(ir.GetAttr(value, index)) - for index in range(len(value.type.elts))], - separator=", ", as_repr=True, as_rtio=as_rtio) - if len(value.type.elts) == 1: - format_string += ",)" - else: - format_string += ")" - elif types.is_function(value.type): - format_string += "" - args.append(self.append(ir.GetAttr(value, '__code__'))) - args.append(self.append(ir.GetAttr(value, '__closure__'))) - elif builtins.is_none(value.type): - format_string += "None" - elif builtins.is_bool(value.type): - format_string += "%.*s" - args.append(self.append(ir.Select(value, - ir.Constant("True", builtins.TStr()), - ir.Constant("False", builtins.TStr())))) - elif builtins.is_int(value.type): - width = builtins.get_int_width(value.type) - if width <= 32: - format_string += "%d" - elif width <= 64: - format_string += "%lld" - else: - assert False - args.append(value) - elif builtins.is_float(value.type): - format_string += "%g" - args.append(value) - elif builtins.is_str(value.type): - if as_repr: - format_string += "\"%.*s\"" - else: - format_string += "%.*s" - args.append(value) - elif builtins.is_listish(value.type): - if builtins.is_list(value.type): - format_string += "["; flush() - elif builtins.is_bytes(value.type): - format_string += "bytes(["; flush() - elif builtins.is_bytearray(value.type): - format_string += "bytearray(["; flush() - elif builtins.is_array(value.type): - format_string += "array(["; flush() - else: - assert False - - length = self.iterable_len(value) - last = self.append(ir.Arith(ast.Sub(loc=None), length, ir.Constant(1, length.type))) - def body_gen(index): - elt = self.iterable_get(value, index) - self.polymorphic_print([elt], separator="", as_repr=True, as_rtio=as_rtio) - is_last = self.append(ir.Compare(ast.Lt(loc=None), index, last)) - head = self.current_block - - if_last = self.current_block = self.add_block("print.comma") - printf(", \x00") - - tail = self.current_block = self.add_block("print.tail") - if_last.append(ir.Branch(tail)) - head.append(ir.BranchIf(is_last, if_last, tail)) - - return self.append(ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, length.type))) - self._make_loop(ir.Constant(0, length.type), - lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, length)), - body_gen) - - if builtins.is_list(value.type): - format_string += "]" - elif (builtins.is_bytes(value.type) or builtins.is_bytearray(value.type) or - builtins.is_array(value.type)): - format_string += "])" - elif builtins.is_range(value.type): - format_string += "range("; flush() - - start = self.append(ir.GetAttr(value, "start")) - stop = self.append(ir.GetAttr(value, "stop")) - step = self.append(ir.GetAttr(value, "step")) - self.polymorphic_print([start, stop, step], separator=", ", as_rtio=as_rtio) - - format_string += ")" - elif builtins.is_exception(value.type): - name = self.append(ir.GetAttr(value, "__name__")) - message = self.append(ir.GetAttr(value, "__message__")) - param1 = self.append(ir.GetAttr(value, "__param0__")) - param2 = self.append(ir.GetAttr(value, "__param1__")) - param3 = self.append(ir.GetAttr(value, "__param2__")) - - format_string += "%.*s(%.*s, %lld, %lld, %lld)" - args += [name, message, param1, param2, param3] - else: - assert False - - format_string += suffix - flush() diff --git a/artiq/compiler/transforms/asttyped_rewriter.py b/artiq/compiler/transforms/asttyped_rewriter.py deleted file mode 100644 index 4c3112be6..000000000 --- a/artiq/compiler/transforms/asttyped_rewriter.py +++ /dev/null @@ -1,526 +0,0 @@ -""" -:class:`ASTTypedRewriter` rewrites a parsetree (:mod:`pythonparser.ast`) -to a typedtree (:mod:`..asttyped`). -""" - -from collections import OrderedDict -from pythonparser import ast, algorithm, diagnostic -from .. import asttyped, types, builtins - -# This visitor will be called for every node with a scope, -# i.e.: class, function, comprehension, lambda -class LocalExtractor(algorithm.Visitor): - def __init__(self, env_stack, engine): - super().__init__() - self.env_stack = env_stack - self.engine = engine - - self.in_root = False - self.in_assign = False - self.typing_env = OrderedDict() - - # which names are global have to be recorded in the current scope - self.global_ = set() - - # which names are nonlocal only affects whether the current scope - # gets a new binding or not, so we throw this away - self.nonlocal_ = set() - - # parameters can't be declared as global or nonlocal - self.params = set() - - def visit_in_assign(self, node, in_assign): - try: - old_in_assign, self.in_assign = self.in_assign, in_assign - return self.visit(node) - finally: - self.in_assign = old_in_assign - - def visit_Assign(self, node): - self.visit(node.value) - self.visit_in_assign(node.targets, in_assign=True) - - def visit_For(self, node): - self.visit(node.iter) - self.visit_in_assign(node.target, in_assign=True) - self.visit(node.body) - self.visit(node.orelse) - - def visit_withitem(self, node): - self.visit(node.context_expr) - self.visit_in_assign(node.optional_vars, in_assign=True) - - def visit_comprehension(self, node): - self.visit(node.iter) - self.visit_in_assign(node.target, in_assign=True) - self.visit(node.ifs) - - def visit_generator(self, node): - if self.in_root: - return - self.in_root = True - self.visit(list(reversed(node.generators))) - self.visit(node.elt) - - visit_ListComp = visit_generator - visit_SetComp = visit_generator - visit_GeneratorExp = visit_generator - - def visit_DictComp(self, node): - if self.in_root: - return - self.in_root = True - self.visit(list(reversed(node.generators))) - self.visit(node.key) - self.visit(node.value) - - def visit_root(self, node): - if self.in_root: - return - self.in_root = True - self.generic_visit(node) - - visit_Module = visit_root # don't look at inner scopes - visit_ClassDef = visit_root - visit_Lambda = visit_root - - def visit_FunctionDef(self, node): - if self.in_root: - self._assignable(node.name) - self.visit_root(node) - - def _assignable(self, name): - assert name is not None - if name not in self.typing_env and name not in self.nonlocal_: - self.typing_env[name] = types.TVar() - - def visit_arg(self, node): - if node.arg in self.params: - diag = diagnostic.Diagnostic("error", - "duplicate parameter '{name}'", {"name": node.arg}, - node.loc) - self.engine.process(diag) - return - self._assignable(node.arg) - self.params.add(node.arg) - - def visit_Name(self, node): - if self.in_assign: - # code like: - # x = 1 - # def f(): - # x = 1 - # creates a new binding for x in f's scope - self._assignable(node.id) - - def visit_Attribute(self, node): - self.visit_in_assign(node.value, in_assign=False) - - def visit_Subscript(self, node): - self.visit_in_assign(node.value, in_assign=False) - self.visit_in_assign(node.slice, in_assign=False) - - def _check_not_in(self, name, names, curkind, newkind, loc): - if name in names: - diag = diagnostic.Diagnostic("error", - "name '{name}' cannot be {curkind} and {newkind} simultaneously", - {"name": name, "curkind": curkind, "newkind": newkind}, loc) - self.engine.process(diag) - return True - return False - - def visit_Global(self, node): - for name, loc in zip(node.names, node.name_locs): - if self._check_not_in(name, self.nonlocal_, "nonlocal", "global", loc) or \ - self._check_not_in(name, self.params, "a parameter", "global", loc): - continue - - self.global_.add(name) - if len(self.env_stack) == 1: - self._assignable(name) # already in global scope - else: - if name not in self.env_stack[1]: - self.env_stack[1][name] = types.TVar() - self.typing_env[name] = self.env_stack[1][name] - - def visit_Nonlocal(self, node): - for name, loc in zip(node.names, node.name_locs): - if self._check_not_in(name, self.global_, "global", "nonlocal", loc) or \ - self._check_not_in(name, self.params, "a parameter", "nonlocal", loc): - continue - - # nonlocal does not search prelude and global scopes - found = False - for outer_env in reversed(self.env_stack[2:]): - if name in outer_env: - found = True - break - if not found: - diag = diagnostic.Diagnostic("error", - "cannot declare name '{name}' as nonlocal: it is not bound in any outer scope", - {"name": name}, - loc, [node.keyword_loc]) - self.engine.process(diag) - continue - - self.nonlocal_.add(name) - - def visit_ExceptHandler(self, node): - self.visit(node.type) - if node.name is not None: - self._assignable(node.name) - for stmt in node.body: - self.visit(stmt) - - -class ASTTypedRewriter(algorithm.Transformer): - """ - :class:`ASTTypedRewriter` converts an untyped AST to a typed AST - where all type fields of non-literals are filled with fresh type variables, - and type fields of literals are filled with corresponding types. - - :class:`ASTTypedRewriter` also discovers the scope of variable bindings - via :class:`LocalExtractor`. - """ - - def __init__(self, engine, prelude): - self.engine = engine - self.globals = None - self.env_stack = [prelude] - self.in_class = None - - def _try_find_name(self, name): - if self.in_class is not None: - typ = self.in_class.constructor_type.attributes.get(name) - if typ is not None: - return typ - - for typing_env in reversed(self.env_stack): - if name in typing_env: - return typing_env[name] - - def _find_name(self, name, loc): - typ = self._try_find_name(name) - if typ is not None: - return typ - - diag = diagnostic.Diagnostic("fatal", - "undefined variable '{name}'", {"name":name}, loc) - self.engine.process(diag) - - # Visitors that replace node with a typed node - # - def visit_Module(self, node): - extractor = LocalExtractor(env_stack=self.env_stack, engine=self.engine) - extractor.visit(node) - - node = asttyped.ModuleT( - typing_env=extractor.typing_env, globals_in_scope=extractor.global_, - body=node.body, loc=node.loc) - self.globals = node.typing_env - - try: - self.env_stack.append(node.typing_env) - return self.generic_visit(node) - finally: - self.env_stack.pop() - - def visit_FunctionDef(self, node): - extractor = LocalExtractor(env_stack=self.env_stack, engine=self.engine) - extractor.visit(node) - - signature_type = self._find_name(node.name, node.name_loc) - - node = asttyped.FunctionDefT( - typing_env=extractor.typing_env, globals_in_scope=extractor.global_, - signature_type=signature_type, return_type=types.TVar(), - name=node.name, args=node.args, returns=node.returns, - body=node.body, decorator_list=node.decorator_list, - keyword_loc=node.keyword_loc, name_loc=node.name_loc, - arrow_loc=node.arrow_loc, colon_loc=node.colon_loc, at_locs=node.at_locs, - loc=node.loc) - - try: - self.env_stack.append(node.typing_env) - return self.generic_visit(node) - finally: - self.env_stack.pop() - - def visit_ClassDef(self, node): - if any(node.bases) or any(node.keywords) or \ - node.starargs is not None or node.kwargs is not None: - diag = diagnostic.Diagnostic("error", - "inheritance is not supported", {}, - node.lparen_loc.join(node.rparen_loc)) - self.engine.process(diag) - - for child in node.body: - if isinstance(child, (ast.Assign, ast.FunctionDef, ast.Pass)): - continue - - diag = diagnostic.Diagnostic("fatal", - "class body must contain only assignments and function definitions", {}, - child.loc) - self.engine.process(diag) - - if node.name in self.env_stack[-1]: - diag = diagnostic.Diagnostic("fatal", - "variable '{name}' is already defined", {"name":node.name}, node.name_loc) - self.engine.process(diag) - - extractor = LocalExtractor(env_stack=self.env_stack, engine=self.engine) - extractor.visit(node) - - # Now we create two types. - # The first type is the type of instances created by the constructor. - # Its attributes are those of the class environment, but wrapped - # appropriately so that they are linked to the class from which they - # originate. - instance_type = types.TInstance(node.name, OrderedDict()) - - # The second type is the type of the constructor itself (in other words, - # the class object): it is simply a singleton type that has the class - # environment as attributes. - constructor_type = types.TConstructor(instance_type) - constructor_type.attributes = extractor.typing_env - instance_type.constructor = constructor_type - - self.env_stack[-1][node.name] = constructor_type - - node = asttyped.ClassDefT( - constructor_type=constructor_type, - name=node.name, - bases=self.visit(node.bases), keywords=self.visit(node.keywords), - starargs=self.visit(node.starargs), kwargs=self.visit(node.kwargs), - body=node.body, - decorator_list=self.visit(node.decorator_list), - keyword_loc=node.keyword_loc, name_loc=node.name_loc, - lparen_loc=node.lparen_loc, star_loc=node.star_loc, - dstar_loc=node.dstar_loc, rparen_loc=node.rparen_loc, - colon_loc=node.colon_loc, at_locs=node.at_locs, - loc=node.loc) - - try: - old_in_class, self.in_class = self.in_class, node - return self.generic_visit(node) - finally: - self.in_class = old_in_class - - def visit_arg(self, node): - if node.annotation is not None: - diag = diagnostic.Diagnostic("fatal", - "type annotations are not supported here", {}, - node.annotation.loc) - self.engine.process(diag) - - return asttyped.argT(type=self._find_name(node.arg, node.loc), - arg=node.arg, annotation=None, - arg_loc=node.arg_loc, colon_loc=node.colon_loc, loc=node.loc) - - def visit_Num(self, node): - if isinstance(node.n, int): - typ = builtins.TInt() - elif isinstance(node.n, float): - typ = builtins.TFloat() - else: - diag = diagnostic.Diagnostic("fatal", - "numeric type {type} is not supported", {"type": node.n.__class__.__name__}, - node.loc) - self.engine.process(diag) - return asttyped.NumT(type=typ, - n=node.n, loc=node.loc) - - def visit_Str(self, node): - if isinstance(node.s, str): - typ = builtins.TStr() - elif isinstance(node.s, bytes): - typ = builtins.TBytes() - else: - assert False - return asttyped.StrT(type=typ, s=node.s, - begin_loc=node.begin_loc, end_loc=node.end_loc, loc=node.loc) - - def visit_Name(self, node): - return asttyped.NameT(type=self._find_name(node.id, node.loc), - id=node.id, ctx=node.ctx, loc=node.loc) - - def visit_NameConstant(self, node): - if node.value is True or node.value is False: - typ = builtins.TBool() - elif node.value is None: - typ = builtins.TNone() - return asttyped.NameConstantT(type=typ, value=node.value, loc=node.loc) - - def visit_Tuple(self, node): - node = self.generic_visit(node) - return asttyped.TupleT(type=types.TTuple([x.type for x in node.elts]), - elts=node.elts, ctx=node.ctx, loc=node.loc) - - def visit_List(self, node): - node = self.generic_visit(node) - node = asttyped.ListT(type=builtins.TList(), - elts=node.elts, ctx=node.ctx, - begin_loc=node.begin_loc, end_loc=node.end_loc, loc=node.loc) - return self.visit(node) - - def visit_Attribute(self, node): - node = self.generic_visit(node) - node = asttyped.AttributeT(type=types.TVar(), - value=node.value, attr=node.attr, ctx=node.ctx, - dot_loc=node.dot_loc, attr_loc=node.attr_loc, loc=node.loc) - return self.visit(node) - - def visit_Slice(self, node): - node = self.generic_visit(node) - node = asttyped.SliceT(type=types.TVar(), - lower=node.lower, upper=node.upper, step=node.step, - bound_colon_loc=node.bound_colon_loc, - step_colon_loc=node.step_colon_loc, - loc=node.loc) - return self.visit(node) - - def visit_Subscript(self, node): - node = self.generic_visit(node) - node = asttyped.SubscriptT(type=types.TVar(), - value=node.value, slice=node.slice, ctx=node.ctx, - begin_loc=node.begin_loc, end_loc=node.end_loc, loc=node.loc) - return self.visit(node) - - def visit_BoolOp(self, node): - node = self.generic_visit(node) - node = asttyped.BoolOpT(type=types.TVar(), - op=node.op, values=node.values, - op_locs=node.op_locs, loc=node.loc) - return self.visit(node) - - def visit_UnaryOp(self, node): - node = self.generic_visit(node) - node = asttyped.UnaryOpT(type=types.TVar(), - op=node.op, operand=node.operand, - loc=node.loc) - return self.visit(node) - - def visit_BinOp(self, node): - node = self.generic_visit(node) - node = asttyped.BinOpT(type=types.TVar(), - left=node.left, op=node.op, right=node.right, - loc=node.loc) - return self.visit(node) - - def visit_Compare(self, node): - node = self.generic_visit(node) - node = asttyped.CompareT(type=types.TVar(), - left=node.left, ops=node.ops, comparators=node.comparators, - loc=node.loc) - return self.visit(node) - - def visit_IfExp(self, node): - node = self.generic_visit(node) - node = asttyped.IfExpT(type=types.TVar(), - test=node.test, body=node.body, orelse=node.orelse, - if_loc=node.if_loc, else_loc=node.else_loc, loc=node.loc) - return self.visit(node) - - def visit_ListComp(self, node): - extractor = LocalExtractor(env_stack=self.env_stack, engine=self.engine) - extractor.visit(node) - - node = asttyped.ListCompT( - typing_env=extractor.typing_env, globals_in_scope=extractor.global_, - type=types.TVar(), - elt=node.elt, generators=node.generators, - begin_loc=node.begin_loc, end_loc=node.end_loc, loc=node.loc) - - try: - self.env_stack.append(node.typing_env) - return self.generic_visit(node) - finally: - self.env_stack.pop() - - def visit_Call(self, node): - node = self.generic_visit(node) - node = asttyped.CallT(type=types.TVar(), iodelay=None, arg_exprs={}, - func=node.func, args=node.args, keywords=node.keywords, - starargs=node.starargs, kwargs=node.kwargs, - star_loc=node.star_loc, dstar_loc=node.dstar_loc, - begin_loc=node.begin_loc, end_loc=node.end_loc, loc=node.loc) - return node - - def visit_Lambda(self, node): - extractor = LocalExtractor(env_stack=self.env_stack, engine=self.engine) - extractor.visit(node) - - node = asttyped.LambdaT( - typing_env=extractor.typing_env, globals_in_scope=extractor.global_, - type=types.TVar(), - args=node.args, body=node.body, - lambda_loc=node.lambda_loc, colon_loc=node.colon_loc, loc=node.loc) - - try: - self.env_stack.append(node.typing_env) - return self.generic_visit(node) - finally: - self.env_stack.pop() - - def visit_ExceptHandler(self, node): - node = self.generic_visit(node) - if node.name is not None: - name_type = self._find_name(node.name, node.name_loc) - else: - name_type = types.TVar() - node = asttyped.ExceptHandlerT( - name_type=name_type, - filter=node.type, name=node.name, body=node.body, - except_loc=node.except_loc, as_loc=node.as_loc, name_loc=node.name_loc, - colon_loc=node.colon_loc, loc=node.loc) - return node - - def visit_Raise(self, node): - node = self.generic_visit(node) - if node.cause: - diag = diagnostic.Diagnostic("error", - "'raise from' syntax is not supported", {}, - node.from_loc) - self.engine.process(diag) - return node - - def visit_For(self, node): - node = self.generic_visit(node) - node = asttyped.ForT( - target=node.target, iter=node.iter, body=node.body, orelse=node.orelse, - trip_count=None, trip_interval=None, - keyword_loc=node.keyword_loc, in_loc=node.in_loc, for_colon_loc=node.for_colon_loc, - else_loc=node.else_loc, else_colon_loc=node.else_colon_loc, loc=node.loc) - return node - - def visit_withitem(self, node): - node = self.generic_visit(node) - node = asttyped.withitemT( - context_expr=node.context_expr, optional_vars=node.optional_vars, - enter_type=types.TVar(), exit_type=types.TVar(), - as_loc=node.as_loc, loc=node.loc) - return node - - # Unsupported visitors - # - def visit_unsupported(self, node): - diag = diagnostic.Diagnostic("fatal", - "this syntax is not supported", {}, - node.loc) - self.engine.process(diag) - - # expr - visit_Dict = visit_unsupported - visit_DictComp = visit_unsupported - visit_Ellipsis = visit_unsupported - visit_GeneratorExp = visit_unsupported - # visit_Set = visit_unsupported - visit_SetComp = visit_unsupported - visit_Starred = visit_unsupported - visit_Yield = visit_unsupported - visit_YieldFrom = visit_unsupported - - # stmt - visit_Delete = visit_unsupported - visit_Import = visit_unsupported - visit_ImportFrom = visit_unsupported diff --git a/artiq/compiler/transforms/cast_monomorphizer.py b/artiq/compiler/transforms/cast_monomorphizer.py deleted file mode 100644 index c0935ff1f..000000000 --- a/artiq/compiler/transforms/cast_monomorphizer.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -:class:`CastMonomorphizer` uses explicit casts to monomorphize -expressions of undetermined integer type to either 32 or 64 bits. -""" - -from pythonparser import algorithm, diagnostic -from .. import types, builtins, asttyped - -class CastMonomorphizer(algorithm.Visitor): - def __init__(self, engine): - self.engine = engine - - def visit_CallT(self, node): - if (types.is_builtin(node.func.type, "int") or - types.is_builtin(node.func.type, "int32") or - types.is_builtin(node.func.type, "int64")): - typ = node.type.find() - if (not types.is_var(typ["width"]) and - len(node.args) == 1 and - builtins.is_int(node.args[0].type) and - types.is_var(node.args[0].type.find()["width"])): - if isinstance(node.args[0], asttyped.BinOpT): - # Binary operations are a bit special: they can widen, and so their - # return type is indeterminate until both argument types are fully known. - # In case we first monomorphize the return type, and then some argument type, - # and argument type is wider than return type, we'll introduce a conflict. - return - - node.args[0].type.unify(typ) - - if types.is_builtin(node.func.type, "int") or \ - types.is_builtin(node.func.type, "round"): - typ = node.type.find() - if types.is_var(typ["width"]): - typ["width"].unify(types.TValue(32)) - - self.generic_visit(node) - - def visit_CoerceT(self, node): - if isinstance(node.value, asttyped.NumT) and \ - builtins.is_int(node.type) and \ - builtins.is_int(node.value.type) and \ - not types.is_var(node.type["width"]) and \ - types.is_var(node.value.type["width"]): - node.value.type.unify(node.type) - - self.generic_visit(node) diff --git a/artiq/compiler/transforms/constant_hoister.py b/artiq/compiler/transforms/constant_hoister.py deleted file mode 100644 index ea51046aa..000000000 --- a/artiq/compiler/transforms/constant_hoister.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -:class:`ConstantHoister` is a code motion transform: -it moves any invariant loads to the earliest point where -they may be executed. -""" - -from .. import types, ir - -class ConstantHoister: - def process(self, functions): - for func in functions: - self.process_function(func) - - def process_function(self, func): - entry = func.entry() - worklist = set(func.instructions()) - moved = set() - while len(worklist) > 0: - insn = worklist.pop() - - if (isinstance(insn, ir.GetAttr) and insn not in moved and - types.is_instance(insn.object().type) and - insn.attr in insn.object().type.constant_attributes): - has_variant_operands = False - index_in_entry = 0 - for operand in insn.operands: - if isinstance(operand, ir.Argument): - pass - elif isinstance(operand, ir.Instruction) and operand.basic_block == entry: - index_in_entry = entry.index(operand) + 1 - else: - has_variant_operands = True - break - - if has_variant_operands: - continue - - insn.remove_from_parent() - entry.instructions.insert(index_in_entry, insn) - moved.add(insn) - - for use in insn.uses: - worklist.add(use) diff --git a/artiq/compiler/transforms/dead_code_eliminator.py b/artiq/compiler/transforms/dead_code_eliminator.py deleted file mode 100644 index 608a46d55..000000000 --- a/artiq/compiler/transforms/dead_code_eliminator.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -:class:`DeadCodeEliminator` is a dead code elimination transform: -it only basic blocks with no predecessors as well as unused -instructions without side effects. -""" - -from .. import ir - -class DeadCodeEliminator: - def __init__(self, engine): - self.engine = engine - - def process(self, functions): - for func in functions: - self.process_function(func) - - def process_function(self, func): - modified = True - while modified: - modified = False - for block in list(func.basic_blocks): - if not any(block.predecessors()) and block != func.entry(): - self.remove_block(block) - modified = True - - modified = True - while modified: - modified = False - for insn in func.instructions(): - # Note that GetLocal is treated as an impure operation: - # the local access validator has to observe it to emit - # a diagnostic for reads of uninitialized locals, and - # it also has to run after the interleaver, but interleaver - # doesn't like to work with IR before DCE. - if isinstance(insn, (ir.Phi, ir.Alloc, ir.GetAttr, ir.GetElem, ir.Coerce, - ir.Arith, ir.Compare, ir.Select, ir.Quote, ir.Closure, - ir.Offset)) \ - and not any(insn.uses): - insn.erase() - modified = True - - def remove_block(self, block): - # block.uses are updated while iterating - for use in set(block.uses): - if isinstance(use, ir.Phi): - use.remove_incoming_block(block) - if not any(use.operands): - self.remove_instruction(use) - elif isinstance(use, ir.SetLocal): - # setlocal %env, %block is only used for lowering finally - use.erase() - else: - assert False - - block.erase() - - def remove_instruction(self, insn): - for use in set(insn.uses): - if isinstance(use, ir.Phi): - use.remove_incoming_value(insn) - if not any(use.operands): - self.remove_instruction(use) - else: - assert False - - insn.erase() diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py deleted file mode 100644 index fdc268d4f..000000000 --- a/artiq/compiler/transforms/inferencer.py +++ /dev/null @@ -1,1777 +0,0 @@ -""" -:class:`Inferencer` performs unification-based inference on a typedtree. -""" - -from collections import OrderedDict -from pythonparser import algorithm, diagnostic, ast -from .. import asttyped, types, builtins -from .typedtree_printer import TypedtreePrinter -from artiq.experiment import kernel - - -def is_nested_empty_list(node): - """If the passed AST node is an empty list, or a regularly nested list thereof, - returns the number of nesting layers, or ``None`` otherwise. - - For instance, ``is_nested_empty_list([]) == 1`` and - ``is_nested_empty_list([[], []]) == 2``, but - ``is_nested_empty_list([[[]], []]) == None`` as the number of nesting layers doesn't - match. - """ - if not isinstance(node, ast.List): - return None - if not node.elts: - return 1 - result = is_nested_empty_list(node.elts[0]) - if result is None: - return None - for elt in node.elts[:1]: - if result != is_nested_empty_list(elt): - return None - return result + 1 - - -class Inferencer(algorithm.Visitor): - """ - :class:`Inferencer` infers types by recursively applying the unification - algorithm. It does not treat inability to infer a concrete type as an error; - the result can still contain type variables. - - :class:`Inferencer` is idempotent, but does not guarantee that it will - perform all possible inference in a single pass. - """ - - def __init__(self, engine): - self.engine = engine - self.function = None # currently visited function, for Return inference - self.in_loop = False - self.has_return = False - - def _unify(self, typea, typeb, loca, locb, makenotes=None, when=""): - try: - typea.unify(typeb) - except types.UnificationError as e: - printer = types.TypePrinter() - - if makenotes: - notes = makenotes(printer, typea, typeb, loca, locb) - else: - notes = [ - diagnostic.Diagnostic("note", - "expression of type {typea}", - {"typea": printer.name(typea)}, - loca) - ] - if locb: - notes.append( - diagnostic.Diagnostic("note", - "expression of type {typeb}", - {"typeb": printer.name(typeb)}, - locb)) - - highlights = [locb] if locb else [] - if e.typea.find() == typea.find() and e.typeb.find() == typeb.find() or \ - e.typeb.find() == typea.find() and e.typea.find() == typeb.find(): - diag = diagnostic.Diagnostic("error", - "cannot unify {typea} with {typeb}{when}", - {"typea": printer.name(typea), "typeb": printer.name(typeb), - "when": when}, - loca, highlights, notes) - else: # give more detail - diag = diagnostic.Diagnostic("error", - "cannot unify {typea} with {typeb}{when}: {fraga} is incompatible with {fragb}", - {"typea": printer.name(typea), "typeb": printer.name(typeb), - "fraga": printer.name(e.typea), "fragb": printer.name(e.typeb), - "when": when}, - loca, highlights, notes) - self.engine.process(diag) - - # makenotes for the case where types of multiple elements are unified - # with the type of parent expression - def _makenotes_elts(self, elts, kind): - def makenotes(printer, typea, typeb, loca, locb): - return [ - diagnostic.Diagnostic("note", - "{kind} of type {typea}", - {"kind": kind, "typea": printer.name(elts[0].type)}, - elts[0].loc), - diagnostic.Diagnostic("note", - "{kind} of type {typeb}", - {"kind": kind, "typeb": printer.name(typeb)}, - locb) - ] - return makenotes - - def visit_ListT(self, node): - self.generic_visit(node) - elt_type_loc = node.loc - for elt in node.elts: - self._unify(node.type["elt"], elt.type, - elt_type_loc, elt.loc, - self._makenotes_elts(node.elts, "a list element")) - elt_type_loc = elt.loc - - def visit_AttributeT(self, node): - self.generic_visit(node) - self._unify_attribute(result_type=node.type, value_node=node.value, - attr_name=node.attr, attr_loc=node.attr_loc, - loc=node.loc) - - def _unify_method_self(self, method_type, attr_name, attr_loc, loc, self_loc): - self_type = types.get_method_self(method_type) - function_type = types.get_method_function(method_type) - - if len(function_type.args) < 1: - diag = diagnostic.Diagnostic("error", - "function '{attr}{type}' of class '{class}' cannot accept a self argument", - {"attr": attr_name, "type": types.TypePrinter().name(function_type), - "class": self_type.name}, - loc) - self.engine.process(diag) - else: - def makenotes(printer, typea, typeb, loca, locb): - if attr_loc is None: - msgb = "reference to an instance with a method '{attr}{typeb}'" - else: - msgb = "reference to a method '{attr}{typeb}'" - - return [ - diagnostic.Diagnostic("note", - "expression of type {typea}", - {"typea": printer.name(typea)}, - loca), - diagnostic.Diagnostic("note", - msgb, - {"attr": attr_name, - "typeb": printer.name(function_type)}, - locb) - ] - - self._unify(self_type, list(function_type.args.values())[0], - self_loc, loc, - makenotes=makenotes, - when=" while inferring the type for self argument") - - def _unify_attribute(self, result_type, value_node, attr_name, attr_loc, loc): - object_type = value_node.type.find() - if not types.is_var(object_type): - if attr_name in object_type.attributes: - def makenotes(printer, typea, typeb, loca, locb): - return [ - diagnostic.Diagnostic("note", - "expression of type {typea}", - {"typea": printer.name(typea)}, - loca), - diagnostic.Diagnostic("note", - "expression of type {typeb}", - {"typeb": printer.name(object_type)}, - value_node.loc) - ] - - attr_type = object_type.attributes[attr_name] - self._unify(result_type, attr_type, loc, None, - makenotes=makenotes, when=" for attribute '{}'".format(attr_name)) - elif types.is_instance(object_type) and \ - attr_name in object_type.constructor.attributes: - attr_type = object_type.constructor.attributes[attr_name].find() - if types.is_function(attr_type): - # Convert to a method. - attr_type = types.TMethod(object_type, attr_type) - self._unify_method_self(attr_type, attr_name, attr_loc, loc, value_node.loc) - elif types.is_rpc(attr_type): - # Convert to a method. We don't have to bother typechecking - # the self argument, since for RPCs anything goes. - attr_type = types.TMethod(object_type, attr_type) - - if not types.is_var(attr_type): - self._unify(result_type, attr_type, - loc, None) - else: - if attr_loc.source_buffer == value_node.loc.source_buffer: - highlights, notes = [value_node.loc], [] - else: - # This happens when the object being accessed is embedded - # from the host program. - note = diagnostic.Diagnostic("note", - "object being accessed", {}, - value_node.loc) - highlights, notes = [], [note] - - diag = diagnostic.Diagnostic("error", - "type {type} does not have an attribute '{attr}'", - {"type": types.TypePrinter().name(object_type), "attr": attr_name}, - attr_loc, highlights, notes) - self.engine.process(diag) - - def _unify_iterable(self, element, collection): - if builtins.is_bytes(collection.type) or builtins.is_bytearray(collection.type): - self._unify(element.type, builtins.get_iterable_elt(collection.type), - element.loc, None) - elif builtins.is_array(collection.type): - array_type = collection.type.find() - elem_dims = array_type["num_dims"].value - 1 - if elem_dims > 0: - elem_type = builtins.TArray(array_type["elt"], types.TValue(elem_dims)) - else: - elem_type = array_type["elt"] - self._unify(element.type, elem_type, element.loc, collection.loc) - elif builtins.is_iterable(collection.type) and not builtins.is_str(collection.type): - rhs_type = collection.type.find() - rhs_wrapped_lhs_type = types.TMono(rhs_type.name, {"elt": element.type}) - self._unify(rhs_wrapped_lhs_type, rhs_type, - element.loc, collection.loc) - elif not types.is_var(collection.type): - diag = diagnostic.Diagnostic("error", - "type {type} is not iterable", - {"type": types.TypePrinter().name(collection.type)}, - collection.loc, []) - self.engine.process(diag) - - def visit_Index(self, node): - self.generic_visit(node) - value = node.value - if types.is_tuple(value.type): - for elt in value.type.find().elts: - self._unify(elt, builtins.TInt(), - value.loc, None) - else: - self._unify(value.type, builtins.TInt(), - value.loc, None) - - def visit_SliceT(self, node): - self.generic_visit(node) - if (node.lower, node.upper, node.step) == (None, None, None): - self._unify(node.type, builtins.TInt32(), - node.loc, None) - else: - self._unify(node.type, builtins.TInt(), - node.loc, None) - for operand in (node.lower, node.upper, node.step): - if operand is not None: - self._unify(operand.type, node.type, - operand.loc, None) - - def visit_ExtSlice(self, node): - diag = diagnostic.Diagnostic("error", - "multi-dimensional slices are not supported", {}, - node.loc, []) - self.engine.process(diag) - - def visit_SubscriptT(self, node): - self.generic_visit(node) - if isinstance(node.slice, ast.Index): - if types.is_tuple(node.slice.value.type): - if types.is_var(node.value.type): - return - if not builtins.is_array(node.value.type): - diag = diagnostic.Diagnostic( - "error", - "multi-dimensional indexing only supported for arrays, not {type}", - {"type": types.TypePrinter().name(node.value.type)}, - node.loc, []) - self.engine.process(diag) - return - num_idxs = len(node.slice.value.type.find().elts) - array_type = node.value.type.find() - num_dims = array_type["num_dims"].value - remaining_dims = num_dims - num_idxs - if remaining_dims < 0: - diag = diagnostic.Diagnostic( - "error", - "too many indices for array of dimension {num_dims}", - {"num_dims": num_dims}, node.slice.loc, []) - self.engine.process(diag) - return - if remaining_dims == 0: - self._unify(node.type, array_type["elt"], node.loc, - node.value.loc) - else: - self._unify( - node.type, - builtins.TArray(array_type["elt"], remaining_dims)) - else: - self._unify_iterable(element=node, collection=node.value) - elif isinstance(node.slice, ast.Slice): - if builtins.is_array(node.value.type): - if node.slice.step is not None: - diag = diagnostic.Diagnostic( - "error", - "strided slicing not yet supported for NumPy arrays", {}, - node.slice.step.loc, []) - self.engine.process(diag) - return - self._unify(node.type, node.value.type, node.loc, node.value.loc) - else: # ExtSlice - pass # error emitted above - - def visit_IfExpT(self, node): - self.generic_visit(node) - self._unify(node.test.type, builtins.TBool(), node.test.loc, None) - self._unify(node.body.type, node.orelse.type, - node.body.loc, node.orelse.loc) - self._unify(node.type, node.body.type, - node.loc, None) - - def visit_BoolOpT(self, node): - self.generic_visit(node) - for value in node.values: - self._unify(node.type, value.type, - node.loc, value.loc, self._makenotes_elts(node.values, "an operand")) - - def visit_UnaryOpT(self, node): - self.generic_visit(node) - operand_type = node.operand.type.find() - if isinstance(node.op, ast.Not): - self._unify(node.type, builtins.TBool(), - node.loc, None) - elif isinstance(node.op, ast.Invert): - if builtins.is_int(operand_type): - self._unify(node.type, operand_type, - node.loc, None) - elif not types.is_var(operand_type): - diag = diagnostic.Diagnostic("error", - "expected '~' operand to be of integer type, not {type}", - {"type": types.TypePrinter().name(operand_type)}, - node.operand.loc) - self.engine.process(diag) - else: # UAdd, USub - if types.is_var(operand_type): - return - - if builtins.is_numeric(operand_type): - self._unify(node.type, operand_type, node.loc, None) - return - - if builtins.is_array(operand_type): - elt = operand_type.find()["elt"] - if builtins.is_numeric(elt): - self._unify(node.type, operand_type, node.loc, None) - return - if types.is_var(elt): - return - - diag = diagnostic.Diagnostic("error", - "expected unary '{op}' operand to be of numeric type, not {type}", - {"op": node.op.loc.source(), - "type": types.TypePrinter().name(operand_type)}, - node.operand.loc) - self.engine.process(diag) - - def visit_CoerceT(self, node): - self.generic_visit(node) - if builtins.is_numeric(node.type) and builtins.is_numeric(node.value.type): - pass - elif (builtins.is_array(node.type) and builtins.is_array(node.value.type) - and builtins.is_numeric(node.type.find()["elt"]) - and builtins.is_numeric(node.value.type.find()["elt"])): - pass - else: - printer = types.TypePrinter() - note = diagnostic.Diagnostic("note", - "expression that required coercion to {typeb}", - {"typeb": printer.name(node.type)}, - node.other_value.loc) - diag = diagnostic.Diagnostic("error", - "cannot coerce {typea} to {typeb}", - {"typea": printer.name(node.value.type), "typeb": printer.name(node.type)}, - node.loc, notes=[note]) - self.engine.process(diag) - - def _coerce_one(self, typ, coerced_node, other_node): - if coerced_node.type.find() == typ.find(): - return coerced_node - elif isinstance(coerced_node, asttyped.CoerceT): - node = coerced_node - node.type.unify(typ) - node.other_value = other_node - else: - node = asttyped.CoerceT(type=typ, value=coerced_node, other_value=other_node, - loc=coerced_node.loc) - self.visit(node) - return node - - def _coerce_numeric(self, nodes, map_return=lambda typ: typ, map_node_type =lambda typ:typ): - # See https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex. - node_types = [] - for node in nodes: - if isinstance(node, asttyped.CoerceT): - # If we already know exactly what we coerce this value to, use that type, - # or we'll get an unification error in case the coerced type is not the same - # as the type of the coerced value. - # Otherwise, use the potentially more specific subtype when considering possible - # coercions, or we may get stuck. - if node.type.fold(False, lambda acc, ty: acc or types.is_var(ty)): - node_types.append(node.value.type) - else: - node_types.append(node.type) - else: - node_types.append(node.type) - node_types = [map_node_type(typ) for typ in node_types] - if any(map(types.is_var, node_types)): # not enough info yet - return - elif not all(map(builtins.is_numeric, node_types)): - err_node = next(filter(lambda node: not builtins.is_numeric(node.type), nodes)) - diag = diagnostic.Diagnostic("error", - "cannot coerce {type} to a numeric type", - {"type": types.TypePrinter().name(err_node.type)}, - err_node.loc, []) - self.engine.process(diag) - return - elif any(map(builtins.is_float, node_types)): - typ = builtins.TFloat() - elif any(map(builtins.is_int, node_types)): - widths = list(map(builtins.get_int_width, node_types)) - if all(widths): - typ = builtins.TInt(types.TValue(max(widths))) - else: - typ = builtins.TInt() - else: - assert False - - return map_return(typ) - - def _order_by_pred(self, pred, left, right): - if pred(left.type): - return left, right - elif pred(right.type): - return right, left - else: - assert False - - def _coerce_binary_broadcast_op(self, left, right, map_return_elt, op_loc): - def num_dims(typ): - if builtins.is_array(typ): - # TODO: If number of dimensions is ever made a non-fixed parameter, - # need to acutally unify num_dims in _coerce_binop/…. - return typ.find()["num_dims"].value - return 0 - - left_dims = num_dims(left.type) - right_dims = num_dims(right.type) - if left_dims != right_dims and left_dims != 0 and right_dims != 0: - # Mismatch (only scalar broadcast supported for now). - note1 = diagnostic.Diagnostic("note", "operand of dimension {num_dims}", - {"num_dims": left_dims}, left.loc) - note2 = diagnostic.Diagnostic("note", "operand of dimension {num_dims}", - {"num_dims": right_dims}, right.loc) - diag = diagnostic.Diagnostic( - "error", "dimensions of '{op}' array operands must match", - {"op": op_loc.source()}, op_loc, [left.loc, right.loc], [note1, note2]) - self.engine.process(diag) - return - - def map_node_type(typ): - if not builtins.is_array(typ): - # This is a single value broadcast across the array. - return typ - return typ.find()["elt"] - - # Figure out result type, handling broadcasts. - result_dims = left_dims if left_dims else right_dims - def map_return(typ): - elt = map_return_elt(typ) - result = builtins.TArray(elt=elt, num_dims=result_dims) - left = builtins.TArray(elt=elt, num_dims=left_dims) if left_dims else elt - right = builtins.TArray(elt=elt, num_dims=right_dims) if right_dims else elt - return (result, left, right) - - return self._coerce_numeric((left, right), - map_return=map_return, - map_node_type=map_node_type) - - def _coerce_binop(self, op, left, right): - if isinstance(op, ast.MatMult): - if types.is_var(left.type) or types.is_var(right.type): - return - - def num_dims(operand): - if not builtins.is_array(operand.type): - diag = diagnostic.Diagnostic( - "error", - "expected matrix multiplication operand to be of array type, not {type}", - { - "op": op.loc.source(), - "type": types.TypePrinter().name(operand.type) - }, op.loc, [operand.loc]) - self.engine.process(diag) - return - num_dims = operand.type.find()["num_dims"].value - if num_dims not in (1, 2): - diag = diagnostic.Diagnostic( - "error", - "expected matrix multiplication operand to be 1- or 2-dimensional, not {type}", - { - "op": op.loc.source(), - "type": types.TypePrinter().name(operand.type) - }, op.loc, [operand.loc]) - self.engine.process(diag) - return - return num_dims - - left_dims = num_dims(left) - if not left_dims: - return - right_dims = num_dims(right) - if not right_dims: - return - - def map_node_type(typ): - return typ.find()["elt"] - - def map_return(typ): - if left_dims == 1: - if right_dims == 1: - result_dims = 0 - else: - result_dims = 1 - elif right_dims == 1: - result_dims = 1 - else: - result_dims = 2 - result = typ if result_dims == 0 else builtins.TArray( - typ, result_dims) - return (result, builtins.TArray(typ, left_dims), - builtins.TArray(typ, right_dims)) - - return self._coerce_numeric((left, right), - map_return=map_return, - map_node_type=map_node_type) - elif builtins.is_array(left.type) or builtins.is_array(right.type): - # Operations on arrays are element-wise (possibly using broadcasting). - - # TODO: Allow only for integer arrays. - # allowed_int_array_ops = (ast.BitAnd, ast.BitOr, ast.BitXor, ast.LShift, - # ast.RShift) - allowed_array_ops = (ast.Add, ast.Mult, ast.FloorDiv, ast.Mod, - ast.Pow, ast.Sub, ast.Div) - if not isinstance(op, allowed_array_ops): - diag = diagnostic.Diagnostic( - "error", "operator '{op}' not valid for array types", - {"op": op.loc.source()}, op.loc) - self.engine.process(diag) - return - - def map_result(typ): - if isinstance(op, ast.Div): - return builtins.TFloat() - return typ - return self._coerce_binary_broadcast_op(left, right, map_result, op.loc) - elif isinstance(op, (ast.BitAnd, ast.BitOr, ast.BitXor, - ast.LShift, ast.RShift)): - # bitwise operators require integers - for operand in (left, right): - if not types.is_var(operand.type) and not builtins.is_int(operand.type): - diag = diagnostic.Diagnostic("error", - "expected '{op}' operand to be of integer type, not {type}", - {"op": op.loc.source(), - "type": types.TypePrinter().name(operand.type)}, - op.loc, [operand.loc]) - self.engine.process(diag) - return - - return self._coerce_numeric((left, right), lambda typ: (typ, typ, typ)) - elif isinstance(op, ast.Add): - # add works on numbers and also collections - if builtins.is_collection(left.type) or builtins.is_collection(right.type): - collection, other = \ - self._order_by_pred(builtins.is_collection, left, right) - if types.is_tuple(collection.type): - pred, kind = types.is_tuple, "tuple" - elif builtins.is_list(collection.type): - pred, kind = builtins.is_list, "list" - else: - assert False - - if types.is_var(other.type): - return - - if not pred(other.type): - printer = types.TypePrinter() - note1 = diagnostic.Diagnostic("note", - "{kind} of type {typea}", - {"typea": printer.name(collection.type), "kind": kind}, - collection.loc) - note2 = diagnostic.Diagnostic("note", - "{typeb}, which cannot be added to a {kind}", - {"typeb": printer.name(other.type), "kind": kind}, - other.loc) - diag = diagnostic.Diagnostic("error", - "expected every '+' operand to be a {kind} in this context", - {"kind": kind}, - op.loc, [other.loc, collection.loc], - [note1, note2]) - self.engine.process(diag) - return - - if types.is_tuple(collection.type): - return types.TTuple(left.type.find().elts + - right.type.find().elts), left.type, right.type - elif builtins.is_list(collection.type): - self._unify(left.type, right.type, - left.loc, right.loc) - return left.type, left.type, right.type - elif (builtins.is_str(left.type) or builtins.is_str(right.type) or - builtins.is_bytes(left.type) or builtins.is_bytes(right.type)): - self._unify(left.type, right.type, - left.loc, right.loc) - return left.type, left.type, right.type - else: - return self._coerce_numeric((left, right), lambda typ: (typ, typ, typ)) - elif isinstance(op, ast.Mult): - # mult works on numbers and also number & collection - if types.is_tuple(left.type) or types.is_tuple(right.type): - tuple_, other = self._order_by_pred(types.is_tuple, left, right) - diag = diagnostic.Diagnostic("error", - "passing tuples to '*' is not supported", {}, - op.loc, [tuple_.loc]) - self.engine.process(diag) - return - elif builtins.is_list(left.type) or builtins.is_list(right.type): - list_, other = self._order_by_pred(builtins.is_list, left, right) - if not builtins.is_int(other.type) and not types.is_var(other.type): - printer = types.TypePrinter() - note1 = diagnostic.Diagnostic("note", - "list operand of type {typea}", - {"typea": printer.name(list_.type)}, - list_.loc) - note2 = diagnostic.Diagnostic("note", - "operand of type {typeb}, which is not a valid repetition amount", - {"typeb": printer.name(other.type)}, - other.loc) - diag = diagnostic.Diagnostic("error", - "expected '*' operands to be a list and an integer in this context", {}, - op.loc, [list_.loc, other.loc], - [note1, note2]) - self.engine.process(diag) - return - - return list_.type, left.type, right.type - else: - return self._coerce_numeric((left, right), lambda typ: (typ, typ, typ)) - elif isinstance(op, (ast.FloorDiv, ast.Mod, ast.Pow, ast.Sub)): - # numeric operators work on any kind of number - return self._coerce_numeric((left, right), lambda typ: (typ, typ, typ)) - elif isinstance(op, ast.Div): - # division always returns a float - return self._coerce_numeric((left, right), - lambda typ: (builtins.TFloat(), builtins.TFloat(), builtins.TFloat())) - else: - diag = diagnostic.Diagnostic("error", - "operator '{op}' is not supported", {"op": op.loc.source()}, - op.loc) - self.engine.process(diag) - return - - def visit_BinOpT(self, node): - self.generic_visit(node) - coerced = self._coerce_binop(node.op, node.left, node.right) - if coerced: - return_type, left_type, right_type = coerced - node.left = self._coerce_one(left_type, node.left, other_node=node.right) - node.right = self._coerce_one(right_type, node.right, other_node=node.left) - - def makenotes(printer, typea, typeb, loca, locb): - def makenote(typ, coerced, loc): - if typ == coerced: - return diagnostic.Diagnostic("note", - "expression of type {type}", - {"type": printer.name(typ)}, - loc) - else: - return diagnostic.Diagnostic("note", - "expression of type {typea} (coerced to {typeb})", - {"typea": printer.name(typ), - "typeb": printer.name(coerced)}, - loc) - - if node.type == return_type: - note = diagnostic.Diagnostic("note", - "expression of type {type}", - {"type": printer.name(typea)}, - loca) - else: - note = diagnostic.Diagnostic("note", - "expression of type {typea} (but {typeb} was expected)", - {"typea": printer.name(typea), - "typeb": printer.name(typeb)}, - loca) - - return [ - makenote(node.left.type, left_type, node.left.loc), - makenote(node.right.type, right_type, node.right.loc), - note - ] - - self._unify(node.type, return_type, - node.loc, None, - makenotes=makenotes) - - def visit_CompareT(self, node): - self.generic_visit(node) - pairs = zip([node.left] + node.comparators, node.comparators) - if all(map(lambda op: isinstance(op, (ast.Is, ast.IsNot)), node.ops)): - for left, right in pairs: - self._unify(left.type, right.type, - left.loc, right.loc) - elif all(map(lambda op: isinstance(op, (ast.In, ast.NotIn)), node.ops)): - for left, right in pairs: - self._unify_iterable(element=left, collection=right) - else: # Eq, NotEq, Lt, LtE, Gt, GtE - operands = [node.left] + node.comparators - operand_types = [operand.type for operand in operands] - if any(map(builtins.is_collection, operand_types)): - for left, right in pairs: - self._unify(left.type, right.type, - left.loc, right.loc) - elif any(map(builtins.is_numeric, operand_types)): - typ = self._coerce_numeric(operands) - if typ: - try: - other_node = next(filter(lambda operand: operand.type.find() == typ.find(), - operands)) - except StopIteration: - # can't find an argument with an exact type, meaning - # the return value is more generic than any of the inputs, meaning - # the type is known (typ is not None), but its width is not - def wide_enough(opreand): - return types.is_mono(opreand.type) and \ - opreand.type.find().name == typ.find().name - other_node = next(filter(wide_enough, operands)) - node.left, *node.comparators = \ - [self._coerce_one(typ, operand, other_node) for operand in operands] - else: - pass # No coercion required. - self._unify(node.type, builtins.TBool(), - node.loc, None) - - def visit_ListCompT(self, node): - if len(node.generators) > 1: - diag = diagnostic.Diagnostic("error", - "multiple for clauses in comprehensions are not supported", {}, - node.generators[1].for_loc) - self.engine.process(diag) - - self.generic_visit(node) - self._unify(node.type, builtins.TList(node.elt.type), - node.loc, None) - - def visit_comprehension(self, node): - if any(node.ifs): - diag = diagnostic.Diagnostic("error", - "if clauses in comprehensions are not supported", {}, - node.if_locs[0]) - self.engine.process(diag) - - self.generic_visit(node) - self._unify_iterable(element=node.target, collection=node.iter) - - def visit_builtin_call(self, node): - typ = node.func.type.find() - - def valid_form(signature): - return diagnostic.Diagnostic("note", - "{func} can be invoked as: {signature}", - {"func": typ.name, "signature": signature}, - node.func.loc) - - def diagnose(valid_forms): - printer = types.TypePrinter() - args = [printer.name(arg.type) for arg in node.args] - args += ["%s=%s" % (kw.arg, printer.name(kw.value.type)) for kw in node.keywords] - - diag = diagnostic.Diagnostic("error", - "{func} cannot be invoked with the arguments ({args})", - {"func": typ.name, "args": ", ".join(args)}, - node.func.loc, notes=valid_forms) - self.engine.process(diag) - - def simple_form(info, arg_types=[], return_type=builtins.TNone()): - self._unify(node.type, return_type, - node.loc, None) - - if len(node.args) == len(arg_types) and len(node.keywords) == 0: - for index, arg_type in enumerate(arg_types): - self._unify(node.args[index].type, arg_type, - node.args[index].loc, None) - else: - diagnose([ valid_form(info) ]) - - if types.is_exn_constructor(typ): - valid_forms = lambda: [ - valid_form("{exn}() -> {exn}".format(exn=typ.name)), - valid_form("{exn}(message:str) -> {exn}".format(exn=typ.name)), - valid_form("{exn}(message:str, param1:numpy.int64) -> {exn}".format(exn=typ.name)), - valid_form("{exn}(message:str, param1:numpy.int64, " - "param2:numpy.int64) -> {exn}".format(exn=typ.name)), - valid_form("{exn}(message:str, param1:numpy.int64, " - "param2:numpy.int64, param3:numpy.int64) " - "-> {exn}".format(exn=typ.name)), - ] - - if len(node.args) == 0 and len(node.keywords) == 0: - pass # Default message, zeroes as parameters - elif len(node.args) >= 1 and len(node.args) <= 4 and len(node.keywords) == 0: - message, *params = node.args - - self._unify(message.type, builtins.TStr(), - message.loc, None) - for param in params: - self._unify(param.type, builtins.TInt64(), - param.loc, None) - else: - diagnose(valid_forms()) - - self._unify(node.type, typ.instance, - node.loc, None) - elif types.is_builtin(typ, "bool"): - valid_forms = lambda: [ - valid_form("bool() -> bool"), - valid_form("bool(x:'a) -> bool") - ] - - if len(node.args) == 0 and len(node.keywords) == 0: - pass # False - elif len(node.args) == 1 and len(node.keywords) == 0: - arg, = node.args - pass # anything goes - else: - diagnose(valid_forms()) - - self._unify(node.type, builtins.TBool(), - node.loc, None) - elif types.is_builtin(typ, "int") or \ - types.is_builtin(typ, "int32") or types.is_builtin(typ, "int64"): - if types.is_builtin(typ, "int"): - valid_forms = lambda: [ - valid_form("int() -> numpy.int?"), - valid_form("int(x:'a) -> numpy.int? where 'a is numeric") - ] - result_typ = builtins.TInt() - elif types.is_builtin(typ, "int32"): - valid_forms = lambda: [ - valid_form("numpy.int32() -> numpy.int32"), - valid_form("numpy.int32(x:'a) -> numpy.int32 where 'a is numeric") - ] - result_typ = builtins.TInt32() - elif types.is_builtin(typ, "int64"): - valid_forms = lambda: [ - valid_form("numpy.int64() -> numpy.int64"), - valid_form("numpy.int64(x:'a) -> numpy.int64 where 'a is numeric") - ] - result_typ = builtins.TInt64() - - self._unify(node.type, result_typ, - node.loc, None) - - if len(node.args) == 0 and len(node.keywords) == 0: - pass # 0 - elif len(node.args) == 1 and len(node.keywords) == 0 and \ - types.is_var(node.args[0].type): - pass # undetermined yet - elif len(node.args) == 1 and len(node.keywords) == 0 and \ - builtins.is_numeric(node.args[0].type): - self._unify(node.type, result_typ, - node.loc, None) - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "float"): - valid_forms = lambda: [ - valid_form("float() -> float"), - valid_form("float(x:'a) -> float where 'a is numeric") - ] - - self._unify(node.type, builtins.TFloat(), - node.loc, None) - - if len(node.args) == 0 and len(node.keywords) == 0: - pass # 0.0 - elif len(node.args) == 1 and len(node.keywords) == 0 and \ - types.is_var(node.args[0].type): - pass # undetermined yet - elif len(node.args) == 1 and len(node.keywords) == 0 and \ - builtins.is_numeric(node.args[0].type): - pass - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "str"): - diag = diagnostic.Diagnostic("error", - "strings currently cannot be constructed", {}, - node.loc) - self.engine.process(diag) - elif types.is_builtin(typ, "array"): - valid_forms = lambda: [ - valid_form("array(x:'a) -> array(elt='b) where 'a is iterable"), - valid_form("array(x:'a, dtype:'b) -> array(elt='b) where 'a is iterable") - ] - - explicit_dtype = None - keywords_acceptable = False - if len(node.keywords) == 0: - keywords_acceptable = True - elif len(node.keywords) == 1: - if node.keywords[0].arg == "dtype": - keywords_acceptable = True - explicit_dtype = node.keywords[0].value - if len(node.args) == 1 and keywords_acceptable: - arg, = node.args - - num_empty_dims = is_nested_empty_list(arg) - if num_empty_dims is not None: - # As a special case, following the behaviour of numpy.array (and - # repr() on ndarrays), consider empty lists to be exactly of the - # number of dimensions given, instead of potentially containing an - # unknown number of extra dimensions. - num_dims = num_empty_dims - - # The ultimate element type will be TVar initially, but we might be - # able to resolve it from context. - elt = arg.type - for _ in range(num_dims): - assert builtins.is_list(elt) - elt = elt.find()["elt"] - else: - # In the absence of any other information (there currently isn't a way - # to specify any), assume that all iterables are expandable into a - # (runtime-checked) rectangular array of the innermost element type. - elt = arg.type - num_dims = 0 - expected_dims = (node.type.find()["num_dims"].value - if builtins.is_array(node.type) else -1) - while True: - if num_dims == expected_dims: - # If we already know the number of dimensions of the result, - # stop so we can disambiguate the (innermost) element type of - # the argument if it is still unknown. - break - if types.is_var(elt): - # Can't make progress here because we don't know how many more - # dimensions might be "hidden" inside. - return - if not builtins.is_iterable(elt) or builtins.is_str(elt): - break - if builtins.is_array(elt): - num_dims += elt.find()["num_dims"].value - else: - num_dims += 1 - elt = builtins.get_iterable_elt(elt) - - if explicit_dtype is not None: - # TODO: Factor out type detection; support quoted type constructors - # (TList(TInt32), …)? - typ = explicit_dtype.type - if types.is_builtin(typ, "int32"): - elt = builtins.TInt32() - elif types.is_builtin(typ, "int64"): - elt = builtins.TInt64() - elif types.is_constructor(typ): - elt = typ.find().instance - else: - diag = diagnostic.Diagnostic( - "error", - "dtype argument of {builtin}() must be a valid constructor", - {"builtin": typ.find().name}, - node.func.loc, - notes=[note]) - self.engine.process(diag) - return - - if num_dims == 0: - note = diagnostic.Diagnostic( - "note", "this expression has type {type}", - {"type": types.TypePrinter().name(arg.type)}, arg.loc) - diag = diagnostic.Diagnostic( - "error", - "the argument of {builtin}() must be of an iterable type", - {"builtin": typ.find().name}, - node.func.loc, - notes=[note]) - self.engine.process(diag) - return - - self._unify(node.type, - builtins.TArray(elt, types.TValue(num_dims)), - node.loc, arg.loc) - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "list"): - valid_forms = lambda: [ - valid_form("list() -> list(elt='a)"), - valid_form("list(x:'a) -> list(elt='b) where 'a is iterable") - ] - - self._unify(node.type, builtins.TList(), node.loc, None) - - if len(node.args) == 0 and len(node.keywords) == 0: - pass # [] - elif len(node.args) == 1 and len(node.keywords) == 0: - arg, = node.args - - if builtins.is_iterable(arg.type): - def makenotes(printer, typea, typeb, loca, locb): - return [ - diagnostic.Diagnostic("note", - "iterator returning elements of type {typea}", - {"typea": printer.name(typea)}, - loca), - diagnostic.Diagnostic("note", - "iterator returning elements of type {typeb}", - {"typeb": printer.name(typeb)}, - locb) - ] - self._unify(node.type.find().params["elt"], - arg.type.find().params["elt"], - node.loc, arg.loc, makenotes=makenotes) - elif types.is_var(arg.type): - pass # undetermined yet - else: - note = diagnostic.Diagnostic("note", - "this expression has type {type}", - {"type": types.TypePrinter().name(arg.type)}, - arg.loc) - diag = diagnostic.Diagnostic("error", - "the argument of {builtin}() must be of an iterable type", - {"builtin": typ.find().name}, - node.func.loc, notes=[note]) - self.engine.process(diag) - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "range"): - valid_forms = lambda: [ - valid_form("range(max:numpy.int?) -> range(elt=numpy.int?)"), - valid_form("range(min:numpy.int?, max:numpy.int?) " - "-> range(elt=numpy.int?)"), - valid_form("range(min:numpy.int?, max:numpy.int?, " - "step:numpy.int?) -> range(elt=numpy.int?)"), - ] - - range_elt = builtins.TInt(types.TVar()) - self._unify(node.type, builtins.TRange(range_elt), - node.loc, None) - - if len(node.args) in (1, 2, 3) and len(node.keywords) == 0: - for arg in node.args: - self._unify(arg.type, range_elt, - arg.loc, None) - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "len"): - valid_forms = lambda: [ - valid_form("len(x:'a) -> numpy.int?"), - ] - - if len(node.args) == 1 and len(node.keywords) == 0: - arg, = node.args - - if builtins.is_range(arg.type): - self._unify(node.type, builtins.get_iterable_elt(arg.type), - node.loc, None) - elif builtins.is_listish(arg.type): - # TODO: should be ssize_t-sized - self._unify(node.type, builtins.TInt32(), - node.loc, None) - elif types.is_var(arg.type): - pass # undetermined yet - else: - note = diagnostic.Diagnostic("note", - "this expression has type {type}", - {"type": types.TypePrinter().name(arg.type)}, - arg.loc) - diag = diagnostic.Diagnostic("error", - "the argument of len() must be of an iterable type", {}, - node.func.loc, notes=[note]) - self.engine.process(diag) - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "round"): - valid_forms = lambda: [ - valid_form("round(x:float) -> numpy.int?"), - ] - - self._unify(node.type, builtins.TInt(), - node.loc, None) - - if len(node.args) == 1 and len(node.keywords) == 0: - arg, = node.args - - self._unify(arg.type, builtins.TFloat(), - arg.loc, None) - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "abs"): - fn = typ.name - - valid_forms = lambda: [ - valid_form("abs(x:numpy.int?) -> numpy.int?"), - valid_form("abs(x:float) -> float") - ] - - if len(node.args) == 1 and len(node.keywords) == 0: - (arg,) = node.args - if builtins.is_int(arg.type) or builtins.is_float(arg.type): - self._unify(arg.type, node.type, - arg.loc, node.loc) - elif types.is_var(arg.type): - pass # undetermined yet - else: - diag = diagnostic.Diagnostic("error", - "the arguments of abs() must be of a numeric type", {}, - node.func.loc) - self.engine.process(diag) - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "min") or types.is_builtin(typ, "max"): - fn = typ.name - - valid_forms = lambda: [ - valid_form("{}(x:numpy.int?, y:numpy.int?) -> numpy.int?".format(fn)), - valid_form("{}(x:float, y:float) -> float".format(fn)) - ] - - if len(node.args) == 2 and len(node.keywords) == 0: - arg0, arg1 = node.args - - self._unify(arg0.type, arg1.type, - arg0.loc, arg1.loc) - - if builtins.is_int(arg0.type) or builtins.is_float(arg0.type): - self._unify(arg0.type, node.type, - arg0.loc, node.loc) - elif types.is_var(arg0.type): - pass # undetermined yet - else: - note = diagnostic.Diagnostic("note", - "this expression has type {type}", - {"type": types.TypePrinter().name(arg0.type)}, - arg0.loc) - diag = diagnostic.Diagnostic("error", - "the arguments of {fn}() must be of a numeric type", - {"fn": fn}, - node.func.loc, notes=[note]) - self.engine.process(diag) - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "print"): - valid_forms = lambda: [ - valid_form("print(args...) -> None"), - ] - - self._unify(node.type, builtins.TNone(), - node.loc, None) - - if len(node.keywords) == 0: - # We can print any arguments. - pass - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "make_array"): - valid_forms = lambda: [ - valid_form("numpy.full(count:int32, value:'a) -> array(elt='a, num_dims=1)"), - valid_form("numpy.full(shape:(int32,)*'b, value:'a) -> array(elt='a, num_dims='b)"), - ] - - if len(node.args) == 2 and len(node.keywords) == 0: - arg0, arg1 = node.args - - if types.is_var(arg0.type): - return # undetermined yet - elif types.is_tuple(arg0.type): - num_dims = len(arg0.type.find().elts) - self._unify(arg0.type, types.TTuple([builtins.TInt32()] * num_dims), - arg0.loc, None) - else: - num_dims = 1 - self._unify(arg0.type, builtins.TInt32(), - arg0.loc, None) - - self._unify(node.type, builtins.TArray(num_dims=num_dims), - node.loc, None) - self._unify(arg1.type, node.type.find()["elt"], - arg1.loc, None) - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "numpy.transpose"): - valid_forms = lambda: [ - valid_form("transpose(x: array(elt='a, num_dims=1)) -> array(elt='a, num_dims=1)"), - valid_form("transpose(x: array(elt='a, num_dims=2)) -> array(elt='a, num_dims=2)") - ] - - if len(node.args) == 1 and len(node.keywords) == 0: - arg, = node.args - - if types.is_var(arg.type): - pass # undetermined yet - elif not builtins.is_array(arg.type): - note = diagnostic.Diagnostic( - "note", "this expression has type {type}", - {"type": types.TypePrinter().name(arg.type)}, arg.loc) - diag = diagnostic.Diagnostic( - "error", - "the argument of {builtin}() must be an array", - {"builtin": typ.find().name}, - node.func.loc, - notes=[note]) - self.engine.process(diag) - else: - num_dims = arg.type.find()["num_dims"].value - if num_dims not in (1, 2): - note = diagnostic.Diagnostic( - "note", "argument is {num_dims}-dimensional", - {"num_dims": num_dims}, arg.loc) - diag = diagnostic.Diagnostic( - "error", - "{builtin}() is currently only supported for up to " - "two-dimensional arrays", {"builtin": typ.find().name}, - node.func.loc, - notes=[note]) - self.engine.process(diag) - else: - self._unify(node.type, arg.type, node.loc, None) - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "rtio_log"): - valid_forms = lambda: [ - valid_form("rtio_log(channel:str, args...) -> None"), - ] - - self._unify(node.type, builtins.TNone(), - node.loc, None) - - if len(node.args) >= 1 and len(node.keywords) == 0: - arg = node.args[0] - - self._unify(arg.type, builtins.TStr(), - arg.loc, None) - else: - diagnose(valid_forms()) - elif types.is_builtin(typ, "now"): - simple_form("now() -> float", - [], builtins.TFloat()) - elif types.is_builtin(typ, "delay"): - simple_form("delay(time:float) -> None", - [builtins.TFloat()]) - elif types.is_builtin(typ, "at"): - simple_form("at(time:float) -> None", - [builtins.TFloat()]) - elif types.is_builtin(typ, "now_mu"): - simple_form("now_mu() -> numpy.int64", - [], builtins.TInt64()) - elif types.is_builtin(typ, "delay_mu"): - simple_form("delay_mu(time_mu:numpy.int64) -> None", - [builtins.TInt64()]) - elif types.is_builtin(typ, "at_mu"): - simple_form("at_mu(time_mu:numpy.int64) -> None", - [builtins.TInt64()]) - elif types.is_constructor(typ): - # An user-defined class. - self._unify(node.type, typ.find().instance, - node.loc, None) - elif types.is_builtin(typ, "kernel"): - # Ignored. - self._unify(node.type, builtins.TNone(), - node.loc, None) - else: - assert False - - def visit_CallT(self, node): - self.generic_visit(node) - - for (sigil_loc, vararg) in ((node.star_loc, node.starargs), - (node.dstar_loc, node.kwargs)): - if vararg: - diag = diagnostic.Diagnostic("error", - "variadic arguments are not supported", {}, - sigil_loc, [vararg.loc]) - self.engine.process(diag) - return - - typ = node.func.type.find() - - if types.is_var(typ): - return # not enough info yet - elif types.is_builtin(typ): - return self.visit_builtin_call(node) - elif types.is_rpc(typ): - self._unify(node.type, typ.ret, - node.loc, None) - return - elif not (types.is_function(typ) or types.is_method(typ)): - diag = diagnostic.Diagnostic("error", - "cannot call this expression of type {type}", - {"type": types.TypePrinter().name(typ)}, - node.func.loc, []) - self.engine.process(diag) - return - - if types.is_function(typ): - typ_arity = typ.arity() - typ_args = typ.args - typ_optargs = typ.optargs - typ_ret = typ.ret - else: - typ_self = types.get_method_self(typ) - typ_func = types.get_method_function(typ) - if types.is_var(typ_func): - return # not enough info yet - elif types.is_rpc(typ_func): - self._unify(node.type, typ_func.ret, - node.loc, None) - return - elif typ_func.arity() == 0: - return # error elsewhere - - method_args = list(typ_func.args.items()) - - self_arg_name, self_arg_type = method_args[0] - self._unify(self_arg_type, typ_self, - node.loc, None) - - typ_arity = typ_func.arity() - 1 - typ_args = OrderedDict(method_args[1:]) - typ_optargs = typ_func.optargs - typ_ret = typ_func.ret - - passed_args = dict() - - if len(node.args) > typ_arity: - note = diagnostic.Diagnostic("note", - "extraneous argument(s)", {}, - node.args[typ_arity].loc.join(node.args[-1].loc)) - diag = diagnostic.Diagnostic("error", - "this function of type {type} accepts at most {num} arguments", - {"type": types.TypePrinter().name(node.func.type), - "num": typ_arity}, - node.func.loc, [], [note]) - self.engine.process(diag) - return - - # Array broadcasting for functions explicitly marked as such. - if len(node.args) == typ_arity and types.is_broadcast_across_arrays(typ): - if typ_arity == 1: - arg_type = node.args[0].type.find() - if builtins.is_array(arg_type): - typ_arg, = typ_args.values() - self._unify(typ_arg, arg_type["elt"], node.args[0].loc, None) - self._unify(node.type, builtins.TArray(typ_ret, arg_type["num_dims"]), - node.loc, None) - return - elif typ_arity == 2: - if any(builtins.is_array(arg.type) for arg in node.args): - ret, arg0, arg1 = self._coerce_binary_broadcast_op( - node.args[0], node.args[1], lambda t: typ_ret, node.loc) - node.args[0] = self._coerce_one(arg0, node.args[0], - other_node=node.args[1]) - node.args[1] = self._coerce_one(arg1, node.args[1], - other_node=node.args[0]) - self._unify(node.type, ret, node.loc, None) - return - - for actualarg, (formalname, formaltyp) in \ - zip(node.args, list(typ_args.items()) + list(typ_optargs.items())): - self._unify(actualarg.type, formaltyp, - actualarg.loc, None) - passed_args[formalname] = actualarg.loc - - for keyword in node.keywords: - if keyword.arg in passed_args: - diag = diagnostic.Diagnostic("error", - "the argument '{name}' has been passed earlier as positional", - {"name": keyword.arg}, - keyword.arg_loc, [passed_args[keyword.arg]]) - self.engine.process(diag) - return - - if keyword.arg in typ_args: - self._unify(keyword.value.type, typ_args[keyword.arg], - keyword.value.loc, None) - elif keyword.arg in typ_optargs: - self._unify(keyword.value.type, typ_optargs[keyword.arg], - keyword.value.loc, None) - else: - note = diagnostic.Diagnostic("note", - "extraneous argument", {}, - keyword.loc) - diag = diagnostic.Diagnostic("error", - "this function of type {type} does not accept argument '{name}'", - {"type": types.TypePrinter().name(node.func.type), - "name": keyword.arg}, - node.func.loc, [], [note]) - self.engine.process(diag) - return - passed_args[keyword.arg] = keyword.arg_loc - - for formalname in typ_args: - if formalname not in passed_args: - note = diagnostic.Diagnostic("note", - "the called function is of type {type}", - {"type": types.TypePrinter().name(node.func.type)}, - node.func.loc) - diag = diagnostic.Diagnostic("error", - "mandatory argument '{name}' is not passed", - {"name": formalname}, - node.begin_loc.join(node.end_loc), [], [note]) - self.engine.process(diag) - return - - self._unify(node.type, typ_ret, - node.loc, None) - - def visit_LambdaT(self, node): - self.generic_visit(node) - signature_type = self._type_from_arguments(node.args, node.body.type) - if signature_type: - self._unify(node.type, signature_type, - node.loc, None) - - def visit_Assign(self, node): - self.generic_visit(node) - for target in node.targets: - self._unify(target.type, node.value.type, - target.loc, node.value.loc) - - def visit_AugAssign(self, node): - self.generic_visit(node) - coerced = self._coerce_binop(node.op, node.target, node.value) - if coerced: - return_type, target_type, value_type = coerced - - if isinstance(node.value, asttyped.CoerceT): - orig_value_type = node.value.value.type - else: - orig_value_type = node.value.type - - try: - node.target.type.unify(return_type) - except types.UnificationError as e: - printer = types.TypePrinter() - note = diagnostic.Diagnostic("note", - "expression of type {typec}", - {"typec": printer.name(orig_value_type)}, - node.value.loc) - diag = diagnostic.Diagnostic("error", - "the result of this operation has type {typeb}, " - "which cannot be assigned to a left-hand side of type {typea}", - {"typea": printer.name(node.target.type), - "typeb": printer.name(return_type)}, - node.op.loc, [node.target.loc], [note]) - self.engine.process(diag) - return - - try: - node.target.type.unify(target_type) - except types.UnificationError as e: - printer = types.TypePrinter() - note = diagnostic.Diagnostic("note", - "expression of type {typec}", - {"typec": printer.name(orig_value_type)}, - node.value.loc) - diag = diagnostic.Diagnostic("error", - "this operation requires the left-hand side of type {typea} " - "to be coerced to {typeb}, which cannot be done", - {"typea": printer.name(node.target.type), - "typeb": printer.name(target_type)}, - node.op.loc, [node.target.loc], [note]) - self.engine.process(diag) - return - - node.value = self._coerce_one(value_type, node.value, other_node=node.target) - - def visit_ForT(self, node): - old_in_loop, self.in_loop = self.in_loop, True - self.generic_visit(node) - self.in_loop = old_in_loop - self._unify_iterable(node.target, node.iter) - - def visit_While(self, node): - old_in_loop, self.in_loop = self.in_loop, True - self.generic_visit(node) - self.in_loop = old_in_loop - - def visit_Break(self, node): - if not self.in_loop: - diag = diagnostic.Diagnostic("error", - "break statement outside of a loop", {}, - node.keyword_loc) - self.engine.process(diag) - - def visit_Continue(self, node): - if not self.in_loop: - diag = diagnostic.Diagnostic("error", - "continue statement outside of a loop", {}, - node.keyword_loc) - self.engine.process(diag) - - def visit_withitemT(self, node): - self.generic_visit(node) - - typ = node.context_expr.type - if (types.is_builtin(typ, "interleave") or types.is_builtin(typ, "sequential") or - types.is_builtin(typ, "parallel")): - # builtin context managers - if node.optional_vars is not None: - self._unify(node.optional_vars.type, builtins.TNone(), - node.optional_vars.loc, None) - elif types.is_instance(typ) or types.is_constructor(typ): - # user-defined context managers - self._unify_attribute(result_type=node.enter_type, value_node=node.context_expr, - attr_name='__enter__', attr_loc=None, loc=node.loc) - self._unify_attribute(result_type=node.exit_type, value_node=node.context_expr, - attr_name='__exit__', attr_loc=None, loc=node.loc) - - printer = types.TypePrinter() - - def check_callback(attr_name, typ, arity): - if types.is_var(typ): - return - - if not (types.is_method(typ) or types.is_function(typ)): - diag = diagnostic.Diagnostic("error", - "attribute '{attr}' of type {manager_type} must be a function", - {"attr": attr_name, - "manager_type": printer.name(node.context_expr.type)}, - node.context_expr.loc) - self.engine.process(diag) - return - - if types.is_method(typ): - typ = types.get_method_function(typ).find() - else: - typ = typ.find() - - if not (len(typ.args) == arity and len(typ.optargs) == 0): - diag = diagnostic.Diagnostic("error", - "function '{attr}{attr_type}' must accept " - "{arity} positional argument{s} and no optional arguments", - {"attr": attr_name, - "attr_type": printer.name(typ), - "arity": arity, "s": "s" if arity > 1 else ""}, - node.context_expr.loc) - self.engine.process(diag) - - for formal_arg_name in list(typ.args)[1:]: - formal_arg_type = typ.args[formal_arg_name] - def makenotes(printer, typea, typeb, loca, locb): - return [ - diagnostic.Diagnostic("note", - "exception handling via context managers is not supported; " - "the argument '{arg}' of function '{attr}{attr_type}' " - "will always be None", - {"arg": formal_arg_name, - "attr": attr_name, - "attr_type": printer.name(typ)}, - loca), - ] - - self._unify(formal_arg_type, builtins.TNone(), - node.context_expr.loc, None, - makenotes=makenotes) - - check_callback('__enter__', node.enter_type, 1) - check_callback('__exit__', node.exit_type, 4) - - if node.optional_vars is not None: - if types.is_method(node.exit_type): - var_type = types.get_method_function(node.exit_type).find().ret - else: - var_type = node.exit_type.find().ret - - def makenotes(printer, typea, typeb, loca, locb): - return [ - diagnostic.Diagnostic("note", - "expression of type {typea}", - {"typea": printer.name(typea)}, - loca), - diagnostic.Diagnostic("note", - "context manager with an '__enter__' method returning {typeb}", - {"typeb": printer.name(typeb)}, - locb) - ] - - self._unify(node.optional_vars.type, var_type, - node.optional_vars.loc, node.context_expr.loc, - makenotes=makenotes) - - elif not types.is_var(typ): - diag = diagnostic.Diagnostic("error", - "value of type {type} cannot act as a context manager", - {"type": types.TypePrinter().name(typ)}, - node.context_expr.loc) - self.engine.process(diag) - - def visit_With(self, node): - self.generic_visit(node) - - for item_node in node.items: - typ = item_node.context_expr.type.find() - if (types.is_builtin(typ, "parallel") or types.is_builtin(typ, "interleave") or - types.is_builtin(typ, "sequential")) and len(node.items) != 1: - diag = diagnostic.Diagnostic("error", - "the '{kind}' context manager must be the only one in a 'with' statement", - {"kind": typ.name}, - node.keyword_loc.join(node.colon_loc)) - self.engine.process(diag) - - def visit_ExceptHandlerT(self, node): - self.generic_visit(node) - - if node.filter is not None: - if not types.is_exn_constructor(node.filter.type): - diag = diagnostic.Diagnostic("error", - "this expression must refer to an exception constructor", - {"type": types.TypePrinter().name(node.filter.type)}, - node.filter.loc) - self.engine.process(diag) - else: - def makenotes(printer, typea, typeb, loca, locb): - return [ - diagnostic.Diagnostic("note", - "expression of type {typea}", - {"typea": printer.name(typea)}, - loca), - diagnostic.Diagnostic("note", - "constructor of an exception of type {typeb}", - {"typeb": printer.name(typeb)}, - locb) - ] - self._unify(node.name_type, node.filter.type.instance, - node.name_loc, node.filter.loc, makenotes) - - def _type_from_arguments(self, node, ret): - self.generic_visit(node) - - for (sigil_loc, vararg) in ((node.star_loc, node.vararg), - (node.dstar_loc, node.kwarg)): - if vararg: - diag = diagnostic.Diagnostic("error", - "variadic arguments are not supported", {}, - sigil_loc, [vararg.loc]) - self.engine.process(diag) - return - - def extract_args(arg_nodes): - args = [(arg_node.arg, arg_node.type) for arg_node in arg_nodes] - return OrderedDict(args) - - return types.TFunction(extract_args(node.args[:len(node.args) - len(node.defaults)]), - extract_args(node.args[len(node.args) - len(node.defaults):]), - ret) - - def visit_arguments(self, node): - self.generic_visit(node) - for arg, default in zip(node.args[len(node.args) - len(node.defaults):], node.defaults): - self._unify(arg.type, default.type, - arg.loc, default.loc) - - def visit_FunctionDefT(self, node): - for index, decorator in enumerate(node.decorator_list): - def eval_attr(attr): - if isinstance(attr.value, asttyped.QuoteT): - return getattr(attr.value.value, attr.attr) - return getattr(eval_attr(attr.value), attr.attr) - if isinstance(decorator, asttyped.AttributeT): - decorator = eval_attr(decorator) - if id(decorator) == id(kernel) or \ - types.is_builtin(decorator.type, "kernel") or \ - isinstance(decorator, asttyped.CallT) and \ - types.is_builtin(decorator.func.type, "kernel"): - continue - - diag = diagnostic.Diagnostic("error", - "decorators are not supported", {}, - node.at_locs[index], []) - self.engine.process(diag) - - try: - old_function, self.function = self.function, node - old_in_loop, self.in_loop = self.in_loop, False - old_has_return, self.has_return = self.has_return, False - - self.generic_visit(node) - - # Lack of return statements is not the only case where the return - # type cannot be inferred. The other one is infinite (possibly mutual) - # recursion. Since Python functions don't have to return a value, - # we ignore that one. - if not self.has_return: - def makenotes(printer, typea, typeb, loca, locb): - return [ - diagnostic.Diagnostic("note", - "function with return type {typea}", - {"typea": printer.name(typea)}, - node.name_loc), - ] - self._unify(node.return_type, builtins.TNone(), - node.name_loc, None, makenotes) - finally: - self.function = old_function - self.in_loop = old_in_loop - self.has_return = old_has_return - - signature_type = self._type_from_arguments(node.args, node.return_type) - if signature_type: - self._unify(node.signature_type, signature_type, - node.name_loc, None) - - visit_QuotedFunctionDefT = visit_FunctionDefT - - def visit_ClassDefT(self, node): - if any(node.decorator_list): - diag = diagnostic.Diagnostic("error", - "decorators are not supported", {}, - node.at_locs[0], [node.decorator_list[0].loc]) - self.engine.process(diag) - - self.generic_visit(node) - - def visit_Return(self, node): - if not self.function: - diag = diagnostic.Diagnostic("error", - "return statement outside of a function", {}, - node.keyword_loc) - self.engine.process(diag) - return - - self.has_return = True - - self.generic_visit(node) - def makenotes(printer, typea, typeb, loca, locb): - return [ - diagnostic.Diagnostic("note", - "function with return type {typea}", - {"typea": printer.name(typea)}, - self.function.name_loc), - diagnostic.Diagnostic("note", - "a statement returning {typeb}", - {"typeb": printer.name(typeb)}, - node.loc) - ] - if node.value is None: - self._unify(self.function.return_type, builtins.TNone(), - self.function.name_loc, node.loc, makenotes) - else: - self._unify(self.function.return_type, node.value.type, - self.function.name_loc, node.value.loc, makenotes) - - def visit_Raise(self, node): - self.generic_visit(node) - - if node.exc is not None: - exc_type = node.exc.type - if types.is_exn_constructor(exc_type): - pass # short form - elif not types.is_var(exc_type) and not builtins.is_exception(exc_type): - diag = diagnostic.Diagnostic("error", - "cannot raise a value of type {type}, which is not an exception", - {"type": types.TypePrinter().name(exc_type)}, - node.loc) - self.engine.process(diag) - - def visit_Assert(self, node): - self.generic_visit(node) - self._unify(node.test.type, builtins.TBool(), - node.test.loc, None) - if node.msg is not None: - if not isinstance(node.msg, asttyped.StrT): - diag = diagnostic.Diagnostic("error", - "assertion message must be a string literal", {}, - node.msg.loc) - self.engine.process(diag) diff --git a/artiq/compiler/transforms/int_monomorphizer.py b/artiq/compiler/transforms/int_monomorphizer.py deleted file mode 100644 index adab3b165..000000000 --- a/artiq/compiler/transforms/int_monomorphizer.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -:class:`IntMonomorphizer` collapses the integer literals of undetermined -width to 32 bits, assuming they fit into 32 bits, or 64 bits if they -do not. -""" - -from pythonparser import algorithm, diagnostic -from .. import types, builtins, asttyped - -class IntMonomorphizer(algorithm.Visitor): - def __init__(self, engine): - self.engine = engine - - def visit_NumT(self, node): - if builtins.is_int(node.type): - if types.is_var(node.type["width"]): - if -2**31 < node.n < 2**31-1: - width = 32 - elif -2**63 < node.n < 2**63-1: - width = 64 - else: - diag = diagnostic.Diagnostic("error", - "integer literal out of range for a signed 64-bit value", {}, - node.loc) - self.engine.process(diag) - return - - node.type["width"].unify(types.TValue(width)) diff --git a/artiq/compiler/transforms/interleaver.py b/artiq/compiler/transforms/interleaver.py deleted file mode 100644 index 1bf9cf5a5..000000000 --- a/artiq/compiler/transforms/interleaver.py +++ /dev/null @@ -1,185 +0,0 @@ -""" -:class:`Interleaver` reorders requests to the RTIO core so that -the timestamp would always monotonically nondecrease. -""" - -from pythonparser import diagnostic - -from .. import types, builtins, ir, iodelay -from ..analyses import domination -from ..algorithms import inline, unroll - -def delay_free_subgraph(root, limit): - visited = set() - queue = root.successors() - while len(queue) > 0: - block = queue.pop() - visited.add(block) - - if block is limit: - continue - - if isinstance(block.terminator(), ir.Delay): - return False - - for successor in block.successors(): - if successor not in visited: - queue.append(successor) - - return True - -def iodelay_of_block(block): - terminator = block.terminator() - if isinstance(terminator, ir.Delay): - # We should be able to fold everything without free variables. - folded_expr = terminator.interval.fold() - assert iodelay.is_const(folded_expr) - return folded_expr.value - else: - return 0 - -def is_pure_delay(insn): - return isinstance(insn, ir.Builtin) and insn.op in ("delay", "delay_mu") - -def is_impure_delay_block(block): - terminator = block.terminator() - return isinstance(terminator, ir.Delay) and \ - not is_pure_delay(terminator.decomposition()) - -class Interleaver: - def __init__(self, engine): - self.engine = engine - - def process(self, functions): - for func in functions: - self.process_function(func) - - def process_function(self, func): - for insn in func.instructions(): - if isinstance(insn, ir.Delay): - if any(insn.interval.free_vars()): - # If a function has free variables in delay expressions, - # that means its IO delay depends on arguments. - # Do not change such functions in any way so that it will - # be successfully inlined and then removed by DCE. - return - - postdom_tree = None - for insn in func.instructions(): - if not isinstance(insn, ir.Interleave): - continue - - # Lazily compute dominators. - if postdom_tree is None: - postdom_tree = domination.PostDominatorTree(func) - - target_block = insn.basic_block - target_time = 0 - source_blocks = insn.basic_block.successors() - source_times = [0 for _ in source_blocks] - - if len(source_blocks) == 1: - # Immediate dominator for a interleave instruction with one successor - # is the first instruction in the body of the statement which created - # it, but below we expect that it would be the first instruction after - # the statement itself. - insn.replace_with(ir.Branch(source_blocks[0])) - continue - - interleave_until = postdom_tree.immediate_dominator(insn.basic_block) - assert interleave_until is not None # no nonlocal flow in `with interleave` - assert interleave_until not in source_blocks - - while len(source_blocks) > 0: - def time_after_block(pair): - index, block = pair - return source_times[index] + iodelay_of_block(block) - - # Always prefer impure blocks (with calls) to pure blocks, because - # impure blocks may expand with smaller delays appearing, and in - # case of a tie, if a pure block is preferred, this would violate - # the timeline monotonicity. - available_source_blocks = list(filter(is_impure_delay_block, source_blocks)) - if not any(available_source_blocks): - available_source_blocks = source_blocks - - index, source_block = min(enumerate(available_source_blocks), key=time_after_block) - source_block_delay = iodelay_of_block(source_block) - - new_target_time = source_times[index] + source_block_delay - target_time_delta = new_target_time - target_time - assert target_time_delta >= 0 - - target_terminator = target_block.terminator() - if isinstance(target_terminator, ir.Interleave): - target_terminator.replace_with(ir.Branch(source_block)) - elif isinstance(target_terminator, (ir.Delay, ir.Branch)): - target_terminator.set_target(source_block) - else: - assert False - - source_terminator = source_block.terminator() - if isinstance(source_terminator, ir.Interleave): - source_terminator.replace_with(ir.Branch(source_terminator.target())) - elif isinstance(source_terminator, ir.Branch): - pass - elif isinstance(source_terminator, ir.BranchIf): - # Skip a delay-free loop/conditional - source_block = postdom_tree.immediate_dominator(source_block) - assert (source_block is not None) - elif isinstance(source_terminator, ir.Return): - break - elif isinstance(source_terminator, ir.Delay): - old_decomp = source_terminator.decomposition() - if is_pure_delay(old_decomp): - if target_time_delta > 0: - new_decomp_expr = ir.Constant(int(target_time_delta), builtins.TInt64()) - new_decomp = ir.Builtin("delay_mu", [new_decomp_expr], builtins.TNone()) - new_decomp.loc = old_decomp.loc - - source_terminator.basic_block.insert(new_decomp, before=source_terminator) - source_terminator.interval = iodelay.Const(target_time_delta) - source_terminator.set_decomposition(new_decomp) - else: - source_terminator.replace_with(ir.Branch(source_terminator.target())) - old_decomp.erase() - else: # It's a call. - need_to_inline = len(source_blocks) > 1 - if need_to_inline: - if old_decomp.static_target_function is None: - diag = diagnostic.Diagnostic("fatal", - "it is not possible to interleave this function call within " - "a 'with interleave:' statement because the compiler could not " - "prove that the same function would always be called", {}, - old_decomp.loc) - self.engine.process(diag) - - inline(old_decomp) - postdom_tree = domination.PostDominatorTree(func) - continue - elif target_time_delta > 0: - source_terminator.interval = iodelay.Const(target_time_delta) - else: - source_terminator.replace_with(ir.Branch(source_terminator.target())) - elif isinstance(source_terminator, ir.Loop): - unroll(source_terminator) - - postdom_tree = domination.PostDominatorTree(func) - continue - else: - assert False - - target_block = source_block - target_time = new_target_time - - new_source_block = postdom_tree.immediate_dominator(source_block) - assert (new_source_block is not None) - assert delay_free_subgraph(source_block, new_source_block) - - if new_source_block == interleave_until: - # We're finished with this branch. - del source_blocks[index] - del source_times[index] - else: - source_blocks[index] = new_source_block - source_times[index] = new_target_time diff --git a/artiq/compiler/transforms/iodelay_estimator.py b/artiq/compiler/transforms/iodelay_estimator.py deleted file mode 100644 index 90bfefdb3..000000000 --- a/artiq/compiler/transforms/iodelay_estimator.py +++ /dev/null @@ -1,327 +0,0 @@ -""" -:class:`IODelayEstimator` calculates the amount of time -elapsed from the point of view of the RTIO core for -every function. -""" - -from pythonparser import ast, algorithm, diagnostic -from .. import types, iodelay, builtins, asttyped - -class _UnknownDelay(Exception): - pass - -class _IndeterminateDelay(Exception): - def __init__(self, cause): - self.cause = cause - -class IODelayEstimator(algorithm.Visitor): - def __init__(self, engine, ref_period): - self.engine = engine - self.ref_period = ref_period - self.changed = False - self.current_delay = iodelay.Const(0) - self.current_args = None - self.current_goto = None - self.current_return = None - - def evaluate(self, node, abort, context): - if isinstance(node, asttyped.NumT): - return iodelay.Const(node.n) - elif isinstance(node, asttyped.CoerceT): - return self.evaluate(node.value, abort, context) - elif isinstance(node, asttyped.NameT): - if self.current_args is None: - note = diagnostic.Diagnostic("note", - "this variable is not an argument", {}, - node.loc) - abort([note]) - elif node.id in [arg.arg for arg in self.current_args.args]: - return iodelay.Var(node.id) - else: - notes = [ - diagnostic.Diagnostic("note", - "this variable is not an argument of the innermost function", {}, - node.loc), - diagnostic.Diagnostic("note", - "only these arguments are in scope of analysis", {}, - self.current_args.loc) - ] - abort(notes) - elif isinstance(node, asttyped.BinOpT): - lhs = self.evaluate(node.left, abort, context) - rhs = self.evaluate(node.right, abort, context) - if isinstance(node.op, ast.Add): - return lhs + rhs - elif isinstance(node.op, ast.Sub): - return lhs - rhs - elif isinstance(node.op, ast.Mult): - return lhs * rhs - elif isinstance(node.op, ast.Div): - return lhs / rhs - elif isinstance(node.op, ast.FloorDiv): - return lhs // rhs - else: - note = diagnostic.Diagnostic("note", - "this operator is not supported {context}", - {"context": context}, - node.op.loc) - abort([note]) - else: - note = diagnostic.Diagnostic("note", - "this expression is not supported {context}", - {"context": context}, - node.loc) - abort([note]) - - def abort(self, message, loc, notes=[]): - diag = diagnostic.Diagnostic("error", message, {}, loc, notes=notes) - raise _IndeterminateDelay(diag) - - def visit_fixpoint(self, node): - while True: - self.changed = False - self.visit(node) - if not self.changed: - return - - def visit_ModuleT(self, node): - try: - for stmt in node.body: - try: - self.visit(stmt) - except _UnknownDelay: - pass # more luck next time? - except _IndeterminateDelay: - pass # we don't care; module-level code is never interleaved - - def visit_function(self, args, body, typ, loc): - old_args, self.current_args = self.current_args, args - old_return, self.current_return = self.current_return, None - old_delay, self.current_delay = self.current_delay, iodelay.Const(0) - try: - self.visit(body) - if not iodelay.is_zero(self.current_delay) and self.current_return is not None: - self.abort("only return statement at the end of the function " - "can be interleaved", self.current_return.loc) - - delay = types.TFixedDelay(self.current_delay.fold()) - except _IndeterminateDelay as error: - delay = types.TIndeterminateDelay(error.cause) - self.current_delay = old_delay - self.current_return = old_return - self.current_args = old_args - - if types.is_indeterminate_delay(delay) and types.is_indeterminate_delay(typ.delay): - # Both delays indeterminate; no point in unifying since that will - # replace the lazy and more specific error with an eager and more generic - # error (unification error of delay(?) with delay(?), which is useless). - return - - try: - old_delay = typ.delay.find() - typ.delay.unify(delay) - if typ.delay.find() != old_delay: - self.changed = True - except types.UnificationError as e: - printer = types.TypePrinter() - diag = diagnostic.Diagnostic("fatal", - "delay {delaya} was inferred for this function, but its delay is already " - "constrained externally to {delayb}", - {"delaya": printer.name(delay), "delayb": printer.name(typ.delay)}, - loc) - self.engine.process(diag) - - def visit_FunctionDefT(self, node): - self.visit(node.args.defaults) - self.visit(node.args.kw_defaults) - - # We can only handle return in tail position. - if isinstance(node.body[-1], ast.Return): - body = node.body[:-1] - else: - body = node.body - self.visit_function(node.args, body, node.signature_type.find(), node.loc) - - visit_QuotedFunctionDefT = visit_FunctionDefT - - def visit_LambdaT(self, node): - self.visit_function(node.args, node.body, node.type.find(), node.loc) - - def get_iterable_length(self, node, context): - def abort(notes): - self.abort("for statement cannot be interleaved because " - "iteration count is indeterminate", - node.loc, notes) - - def evaluate(node): - return self.evaluate(node, abort, context) - - if isinstance(node, asttyped.CallT) and types.is_builtin(node.func.type, "range"): - range_min, range_max, range_step = iodelay.Const(0), None, iodelay.Const(1) - if len(node.args) == 3: - range_min, range_max, range_step = map(evaluate, node.args) - elif len(node.args) == 2: - range_min, range_max = map(evaluate, node.args) - elif len(node.args) == 1: - range_max, = map(evaluate, node.args) - return (range_max - range_min) // range_step - else: - note = diagnostic.Diagnostic("note", - "this value is not a constant range literal", {}, - node.loc) - abort([note]) - - def visit_ForT(self, node): - self.visit(node.iter) - - old_goto, self.current_goto = self.current_goto, None - old_delay, self.current_delay = self.current_delay, iodelay.Const(0) - self.visit(node.body) - if iodelay.is_zero(self.current_delay): - self.current_delay = old_delay - else: - if self.current_goto is not None: - self.abort("loop iteration count is indeterminate because of control flow", - self.current_goto.loc) - - context = "in an iterable used in a for loop that is being interleaved" - node.trip_count = self.get_iterable_length(node.iter, context).fold() - node.trip_interval = self.current_delay.fold() - self.current_delay = old_delay + node.trip_interval * node.trip_count - self.current_goto = old_goto - - self.visit(node.orelse) - - def visit_goto(self, node): - self.current_goto = node - - visit_Break = visit_goto - visit_Continue = visit_goto - - def visit_control_flow(self, kind, node): - old_delay, self.current_delay = self.current_delay, iodelay.Const(0) - self.generic_visit(node) - if not iodelay.is_zero(self.current_delay): - self.abort("{} cannot be interleaved".format(kind), node.loc) - self.current_delay = old_delay - - visit_If = lambda self, node: self.visit_control_flow("if statement", node) - visit_IfExpT = lambda self, node: self.visit_control_flow("if expression", node) - visit_Try = lambda self, node: self.visit_control_flow("try statement", node) - - def visit_While(self, node): - old_goto, self.current_goto = self.current_goto, None - self.visit_control_flow("while statement", node) - self.current_goto = old_goto - - def visit_Return(self, node): - self.current_return = node - - def visit_With(self, node): - self.visit(node.items) - - context_expr = node.items[0].context_expr - if len(node.items) == 1 and types.is_builtin(context_expr.type, "interleave"): - try: - delays = [] - for stmt in node.body: - old_delay, self.current_delay = self.current_delay, iodelay.Const(0) - self.visit(stmt) - delays.append(self.current_delay) - self.current_delay = old_delay - - if any(delays): - self.current_delay += iodelay.Max(delays) - except _IndeterminateDelay as error: - # Interleave failures inside `with` statements are hard failures, - # since there's no chance that the code will never actually execute - # inside a `with` statement after all. - note = diagnostic.Diagnostic("note", - "while interleaving this 'with interleave:' statement", {}, - node.loc) - error.cause.notes += [note] - self.engine.process(error.cause) - - flow_stmt = None - if self.current_goto is not None: - flow_stmt = self.current_goto - elif self.current_return is not None: - flow_stmt = self.current_return - - if flow_stmt is not None: - note = diagnostic.Diagnostic("note", - "this '{kind}' statement transfers control out of " - "the 'with interleave:' statement", - {"kind": flow_stmt.keyword_loc.source()}, - flow_stmt.loc) - diag = diagnostic.Diagnostic("error", - "cannot interleave this 'with interleave:' statement", {}, - node.keyword_loc.join(node.colon_loc), notes=[note]) - self.engine.process(diag) - - elif len(node.items) == 1 and types.is_builtin(context_expr.type, "sequential"): - self.visit(node.body) - else: - self.abort("with statement cannot be interleaved", node.loc) - - def visit_CallT(self, node): - typ = node.func.type.find() - def abort(notes): - self.abort("call cannot be interleaved because " - "an argument cannot be statically evaluated", - node.loc, notes) - - if types.is_builtin(typ, "delay"): - value = self.evaluate(node.args[0], abort=abort, - context="as an argument for delay()") - call_delay = iodelay.SToMU(value, ref_period=self.ref_period) - elif types.is_builtin(typ, "delay_mu"): - value = self.evaluate(node.args[0], abort=abort, - context="as an argument for delay_mu()") - call_delay = value - elif not types.is_builtin(typ): - if types.is_function(typ) or types.is_rpc(typ): - offset = 0 - elif types.is_method(typ): - offset = 1 - typ = types.get_method_function(typ) - else: - assert False - - if types.is_rpc(typ): - call_delay = iodelay.Const(0) - else: - delay = typ.find().delay.find() - if types.is_var(delay): - raise _UnknownDelay() - elif delay.is_indeterminate(): - note = diagnostic.Diagnostic("note", - "function called here", {}, - node.loc) - cause = delay.cause - cause = diagnostic.Diagnostic(cause.level, cause.reason, cause.arguments, - cause.location, cause.highlights, - cause.notes + [note]) - raise _IndeterminateDelay(cause) - elif delay.is_fixed(): - args = {} - for kw_node in node.keywords: - args[kw_node.arg] = kw_node.value - for arg_name, arg_node in zip(list(typ.args)[offset:], node.args): - args[arg_name] = arg_node - - free_vars = delay.duration.free_vars() - node.arg_exprs = { - arg: self.evaluate(args[arg], abort=abort, - context="in the expression for argument '{}' " - "that affects I/O delay".format(arg)) - for arg in free_vars - } - call_delay = delay.duration.fold(node.arg_exprs) - else: - assert False - else: - call_delay = iodelay.Const(0) - - self.current_delay += call_delay - node.iodelay = call_delay diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py deleted file mode 100644 index 61f66599c..000000000 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ /dev/null @@ -1,1656 +0,0 @@ -""" -:class:`LLVMIRGenerator` transforms ARTIQ intermediate representation -into LLVM intermediate representation. -""" - -import os, re, types as pytypes, numpy -from collections import defaultdict -from pythonparser import ast, diagnostic -from llvmlite import ir as ll, binding as llvm -from ...language import core as language_core -from .. import types, builtins, ir -from ..embedding import SpecializedFunction - - -llvoid = ll.VoidType() -llunit = ll.LiteralStructType([]) -lli1 = ll.IntType(1) -lli8 = ll.IntType(8) -lli32 = ll.IntType(32) -lli64 = ll.IntType(64) -lldouble = ll.DoubleType() -llptr = ll.IntType(8).as_pointer() -llptrptr = ll.IntType(8).as_pointer().as_pointer() -llslice = ll.LiteralStructType([llptr, lli32]) -llsliceptr = ll.LiteralStructType([llptr, lli32]).as_pointer() -llmetadata = ll.MetaDataType() - - -def memoize(generator): - def memoized(self, *args): - key = (generator,) + args - try: - return self.cache[key] - except KeyError: - result = generator(self, *args) - self.cache[key] = result - return result - return memoized - - -class ABILayoutInfo: - """Caches DataLayout size/alignment lookup results. - - llvmlite's Type.get_abi_{size, alignment}() are implemented in a very - inefficient way, in particular _get_ll_pointer_type() used to construct the - corresponding llvm::Type is. We thus cache the results, optionally directly - using the compiler type as a key. - - (This is a separate class for use with @memoize.) - """ - - def __init__(self, lldatalayout, llcontext, llty_of_type): - self.cache = {} - self.lldatalayout = lldatalayout - self.llcontext = llcontext - self.llty_of_type = llty_of_type - - @memoize - def get_size_align(self, llty): - lowered = llty._get_ll_pointer_type(self.lldatalayout, self.llcontext) - return (self.lldatalayout.get_pointee_abi_size(lowered), - self.lldatalayout.get_pointee_abi_alignment(lowered)) - - @memoize - def get_size_align_for_type(self, typ): - return self.get_size_align(self.llty_of_type(typ)) - - -class LLVMIRGenerator: - def __init__(self, engine, module_name, target, embedding_map): - self.engine = engine - self.target = target - self.embedding_map = embedding_map - self.llcontext = target.llcontext - self.llmodule = ll.Module(context=self.llcontext, name=module_name) - self.llmodule.triple = target.triple - self.llmodule.data_layout = target.data_layout - self.lldatalayout = llvm.create_target_data(self.llmodule.data_layout) - self.abi_layout_info = ABILayoutInfo(self.lldatalayout, self.llcontext, - self.llty_of_type) - self.function_flags = None - self.llfunction = None - self.llmap = {} - self.llobject_map = {} - self.phis = [] - self.empty_metadata = self.llmodule.add_metadata([]) - self.quote_fail_msg = None - - def needs_sret(self, lltyp, may_be_large=True): - if isinstance(lltyp, ll.VoidType): - return False - elif isinstance(lltyp, ll.IntType): - return False - elif isinstance(lltyp, ll.PointerType): - return False - elif may_be_large and isinstance(lltyp, ll.DoubleType): - return False - elif may_be_large and isinstance(lltyp, ll.LiteralStructType) \ - and len(lltyp.elements) <= 2: - return not any([self.needs_sret(elt, may_be_large=False) for elt in lltyp.elements]) - else: - assert isinstance(lltyp, ll.Type) - return True - - def has_sret(self, functy): - llretty = self.llty_of_type(functy.ret, for_return=True) - return self.needs_sret(llretty) - - def llty_of_type(self, typ, bare=False, for_return=False): - typ = typ.find() - if types.is_tuple(typ): - return ll.LiteralStructType([self.llty_of_type(eltty) for eltty in typ.elts]) - elif types.is_rpc(typ) or types.is_external_function(typ): - if for_return: - return llvoid - else: - return llunit - elif types._is_pointer(typ): - return ll.PointerType(self.llty_of_type(typ["elt"])) - elif types.is_function(typ): - sretarg = [] - llretty = self.llty_of_type(typ.ret, for_return=True) - if self.needs_sret(llretty): - sretarg = [llretty.as_pointer()] - llretty = llvoid - - envarg = llptr - llty = ll.FunctionType(args=sretarg + [envarg] + - [self.llty_of_type(typ.args[arg]) - for arg in typ.args] + - [self.llty_of_type(ir.TOption(typ.optargs[arg])) - for arg in typ.optargs], - return_type=llretty) - - if bare: - return llty - else: - return ll.LiteralStructType([envarg, llty.as_pointer()]) - elif types.is_method(typ): - llfunty = self.llty_of_type(types.get_method_function(typ)) - llselfty = self.llty_of_type(types.get_method_self(typ)) - return ll.LiteralStructType([llfunty, llselfty]) - elif builtins.is_none(typ): - if for_return: - return llvoid - else: - return llunit - elif builtins.is_bool(typ): - return lli1 - elif builtins.is_int(typ): - return ll.IntType(builtins.get_int_width(typ)) - elif builtins.is_float(typ): - return lldouble - elif builtins.is_array(typ): - llshapety = self.llty_of_type(typ.attributes["shape"]) - llbufferty = self.llty_of_type(typ.attributes["buffer"]) - return ll.LiteralStructType([llbufferty, llshapety]) - elif builtins.is_listish(typ): - lleltty = self.llty_of_type(builtins.get_iterable_elt(typ)) - return ll.LiteralStructType([lleltty.as_pointer(), lli32]) - elif builtins.is_range(typ): - lleltty = self.llty_of_type(builtins.get_iterable_elt(typ)) - return ll.LiteralStructType([lleltty, lleltty, lleltty]) - elif ir.is_basic_block(typ): - return llptr - elif ir.is_option(typ): - return ll.LiteralStructType([lli1, self.llty_of_type(typ.params["value"])]) - elif ir.is_keyword(typ): - return ll.LiteralStructType([llslice, self.llty_of_type(typ.params["value"])]) - elif ir.is_environment(typ): - llty = self.llcontext.get_identified_type("env.{}".format(typ.env_name)) - if llty.elements is None: - llty.elements = [self.llty_of_type(typ.params[name]) for name in typ.params] - - if bare: - return llty - else: - return llty.as_pointer() - else: # Catch-all for exceptions and custom classes - if builtins.is_exception(typ): - name = "C.Exception" # they all share layout - elif types.is_constructor(typ): - name = "C.{}".format(typ.name) - else: - name = "I.{}".format(typ.name) - - llty = self.llcontext.get_identified_type(name) - if llty.elements is None: - # First setting elements to [] will allow us to handle - # self-referential types. - llty.elements = [] - llty.elements = [self.llty_of_type(attrtyp) - for attrtyp in typ.attributes.values()] - - if bare or not builtins.is_allocated(typ): - return llty - else: - return llty.as_pointer() - - def llstr_of_str(self, value, name=None, linkage="private", unnamed_addr=True): - if isinstance(value, str): - as_bytes = value.encode("utf-8") - else: - as_bytes = value - - if name is None: - sanitized_str = re.sub(rb"[^a-zA-Z0-9_.]", b"", as_bytes[:20]).decode('ascii') - name = self.llmodule.get_unique_name("S.{}".format(sanitized_str)) - - llstr = self.llmodule.globals.get(name) - if llstr is None: - llstrty = ll.ArrayType(lli8, len(as_bytes)) - llstr = ll.GlobalVariable(self.llmodule, llstrty, name) - llstr.global_constant = True - llstr.initializer = ll.Constant(llstrty, bytearray(as_bytes)) - llstr.linkage = linkage - llstr.unnamed_addr = unnamed_addr - return llstr.bitcast(llptr) - - def llconst_of_const(self, const): - llty = self.llty_of_type(const.type) - if const.value is None: - if isinstance(llty, ll.PointerType): - return ll.Constant(llty, None) - else: - return ll.Constant(llty, []) - elif const.value is True: - return ll.Constant(llty, True) - elif const.value is False: - return ll.Constant(llty, False) - elif isinstance(const.value, (int, float)): - return ll.Constant(llty, const.value) - elif isinstance(const.value, (str, bytes)): - if isinstance(const.value, str): - value = const.value.encode('utf-8') - else: - value = const.value - - llptr = self.llstr_of_str(const.value, linkage="private", unnamed_addr=True) - lllen = ll.Constant(lli32, len(const.value)) - return ll.Constant(llty, (llptr, lllen)) - else: - assert False - - def llbuiltin(self, name): - llglobal = self.llmodule.globals.get(name) - if llglobal is not None: - return llglobal - - if name in "llvm.donothing": - llty = ll.FunctionType(llvoid, []) - elif name == "llvm.floor.f64": - llty = ll.FunctionType(lldouble, [lldouble]) - elif name == "llvm.round.f64": - llty = ll.FunctionType(lldouble, [lldouble]) - elif name == "llvm.pow.f64": - llty = ll.FunctionType(lldouble, [lldouble, lldouble]) - elif name == "llvm.powi.f64": - llty = ll.FunctionType(lldouble, [lldouble, lli32]) - elif name == "llvm.copysign.f64": - llty = ll.FunctionType(lldouble, [lldouble, lldouble]) - elif name == "llvm.stacksave": - llty = ll.FunctionType(llptr, []) - elif name == "llvm.stackrestore": - llty = ll.FunctionType(llvoid, [llptr]) - elif name == "__py_modsi3": - llty = ll.FunctionType(lli32, [lli32, lli32]) - elif name == "__py_moddi3": - llty = ll.FunctionType(lli64, [lli64, lli64]) - elif name == "__py_moddf3": - llty = ll.FunctionType(lldouble, [lldouble, lldouble]) - elif name == self.target.print_function: - llty = ll.FunctionType(llvoid, [llptr], var_arg=True) - elif name == "rtio_log": - llty = ll.FunctionType(llvoid, [llptr], var_arg=True) - elif name == "__artiq_personality": - llty = ll.FunctionType(lli32, [], var_arg=True) - elif name == "__artiq_raise": - llty = ll.FunctionType(llvoid, [self.llty_of_type(builtins.TException())]) - elif name == "__artiq_reraise": - llty = ll.FunctionType(llvoid, []) - elif name == "memcmp": - llty = ll.FunctionType(lli32, [llptr, llptr, lli32]) - elif name == "rpc_send": - llty = ll.FunctionType(llvoid, [lli32, llsliceptr, llptrptr]) - elif name == "rpc_send_async": - llty = ll.FunctionType(llvoid, [lli32, llsliceptr, llptrptr]) - elif name == "rpc_recv": - llty = ll.FunctionType(lli32, [llptr]) - - # with now-pinning - elif name == "now": - llty = lli64 - - # without now-pinning - elif name == "now_mu": - llty = ll.FunctionType(lli64, []) - elif name == "at_mu": - llty = ll.FunctionType(llvoid, [lli64]) - elif name == "delay_mu": - llty = ll.FunctionType(llvoid, [lli64]) - - else: - assert False - - if isinstance(llty, ll.FunctionType): - llglobal = ll.Function(self.llmodule, llty, name) - if name in ("__artiq_raise", "__artiq_reraise", "llvm.trap"): - llglobal.attributes.add("noreturn") - if name in ("rtio_log", "rpc_send", "rpc_send_async", - self.target.print_function): - llglobal.attributes.add("nounwind") - if name.find("__py_") == 0: - llglobal.linkage = 'linkonce_odr' - self.emit_intrinsic(name, llglobal) - else: - llglobal = ll.GlobalVariable(self.llmodule, llty, name) - - return llglobal - - def emit_intrinsic(self, name, llfun): - llbuilder = ll.IRBuilder() - llbuilder.position_at_end(llfun.append_basic_block("entry")) - - if name == "__py_modsi3" or name == "__py_moddi3": - if name == "__py_modsi3": - llty = lli32 - elif name == "__py_moddi3": - llty = lli64 - else: - assert False - - """ - Reference Objects/intobject.c - xdivy = x / y; - xmody = (long)(x - (unsigned long)xdivy * y); - /* If the signs of x and y differ, and the remainder is non-0, - * C89 doesn't define whether xdivy is now the floor or the - * ceiling of the infinitely precise quotient. We want the floor, - * and we have it iff the remainder's sign matches y's. - */ - if (xmody && ((y ^ xmody) < 0) /* i.e. and signs differ */) { - xmody += y; - // ... - } - """ - llx, lly = llfun.args - llxdivy = llbuilder.sdiv(llx, lly) - llxremy = llbuilder.srem(llx, lly) - - llxmodynonzero = llbuilder.icmp_signed('!=', llxremy, ll.Constant(llty, 0)) - lldiffsign = llbuilder.icmp_signed('<', llbuilder.xor(llx, lly), ll.Constant(llty, 0)) - - llcond = llbuilder.and_(llxmodynonzero, lldiffsign) - with llbuilder.if_then(llcond): - llbuilder.ret(llbuilder.add(llxremy, lly)) - llbuilder.ret(llxremy) - elif name == "__py_moddf3": - """ - Reference Objects/floatobject.c - mod = fmod(vx, wx); - /* fmod is typically exact, so vx-mod is *mathematically* an - exact multiple of wx. But this is fp arithmetic, and fp - vx - mod is an approximation; the result is that div may - not be an exact integral value after the division, although - it will always be very close to one. - */ - // ... - if (mod) { - /* ensure the remainder has the same sign as the denominator */ - if ((wx < 0) != (mod < 0)) { - mod += wx; - // ... - } - } - else { - /* the remainder is zero, and in the presence of signed zeroes - fmod returns different results across platforms; ensure - it has the same sign as the denominator; we'd like to do - "mod = wx * 0.0", but that may get optimized away */ - mod *= mod; /* hide "mod = +0" from optimizer */ - if (wx < 0.0) - mod = -mod; - } - """ - llv, llw = llfun.args - llrem = llbuilder.frem(llv, llw) - - llremnonzero = llbuilder.fcmp_unordered('!=', llrem, ll.Constant(lldouble, 0.0)) - llwltzero = llbuilder.fcmp_ordered('<', llw, ll.Constant(lldouble, 0.0)) - llremltzero = llbuilder.fcmp_ordered('<', llrem, ll.Constant(lldouble, 0.0)) - lldiffsign = llbuilder.icmp_unsigned('!=', llwltzero, llremltzero) - - llcond = llbuilder.and_(llremnonzero, lldiffsign) - with llbuilder.if_then(llcond): - llbuilder.ret(llbuilder.fadd(llrem, llw)) - llbuilder.ret(llrem) - else: - assert False - - def get_function(self, typ, name): - llfun = self.llmodule.globals.get(name) - if llfun is None: - llfunty = self.llty_of_type(typ, bare=True) - llfun = ll.Function(self.llmodule, llfunty, name) - - llretty = self.llty_of_type(typ.find().ret, for_return=True) - if self.needs_sret(llretty): - llfun.args[0].add_attribute('sret') - return llfun - - def get_function_with_undef_env(self, typ, name): - llfun = self.get_function(typ, name) - llclosure = ll.Constant(self.llty_of_type(typ), [ - ll.Constant(llptr, ll.Undefined), - llfun - ]) - return llclosure - - def map(self, value): - if isinstance(value, (ir.Argument, ir.Instruction, ir.BasicBlock)): - return self.llmap[value] - elif isinstance(value, ir.Constant): - return self.llconst_of_const(value) - elif isinstance(value, ir.Function): - return self.get_function(value.type, value.name) - else: - assert False - - def process(self, functions, attribute_writeback): - for func in functions: - self.process_function(func) - - if attribute_writeback and self.embedding_map is not None: - self.emit_attribute_writeback() - - return self.llmodule - - def emit_attribute_writeback(self): - llobjects = defaultdict(lambda: []) - - for obj_id, obj_ref, obj_typ in self.embedding_map.iter_objects(): - llobject = self.llmodule.globals.get("O.{}".format(obj_id)) - if llobject is not None: - llobjects[obj_typ].append(llobject.bitcast(llptr)) - - llrpcattrty = self.llcontext.get_identified_type("A") - llrpcattrty.elements = [lli32, llslice, llslice] - - lldescty = self.llcontext.get_identified_type("D") - lldescty.elements = [llrpcattrty.as_pointer().as_pointer(), llptr.as_pointer()] - - lldescs = [] - for typ in llobjects: - if "__objectid__" not in typ.attributes: - continue - - if types.is_constructor(typ): - type_name = "C.{}".format(typ.name) - else: - type_name = "I.{}".format(typ.name) - - def llrpcattr_of_attr(offset, name, typ): - def rpc_tag_error(typ): - print(typ) - assert False - - if name == "__objectid__": - rpctag = b"" - else: - rpctag = b"Os" + ir.rpc_tag(typ, error_handler=rpc_tag_error) + b":n" - - llrpcattrinit = ll.Constant(llrpcattrty, [ - ll.Constant(lli32, offset), - self.llconst_of_const(ir.Constant(rpctag, builtins.TStr())), - self.llconst_of_const(ir.Constant(name, builtins.TStr())) - ]) - - if name == "__objectid__": - return self.get_or_define_global(name, llrpcattrty, llrpcattrinit) - - llrpcattr = ll.GlobalVariable(self.llmodule, llrpcattrty, - name="A.{}.{}".format(type_name, name)) - llrpcattr.initializer = llrpcattrinit - llrpcattr.global_constant = True - llrpcattr.unnamed_addr = True - llrpcattr.linkage = 'private' - - return llrpcattr - - offset = 0 - llrpcattrs = [] - for attr in typ.attributes: - attrtyp = typ.attributes[attr] - size, alignment = self.abi_layout_info.get_size_align_for_type(attrtyp) - - if offset % alignment != 0: - offset += alignment - (offset % alignment) - - if types.is_instance(typ) and attr not in typ.constant_attributes: - try: - llrpcattrs.append(llrpcattr_of_attr(offset, attr, attrtyp)) - except ValueError: - pass - - offset += size - - if len(llrpcattrs) == 1: - # Don't bother serializing objects that only have __objectid__ - # since there's nothing to writeback anyway. - continue - - llrpcattraryty = ll.ArrayType(llrpcattrty.as_pointer(), len(llrpcattrs) + 1) - llrpcattrary = ll.GlobalVariable(self.llmodule, llrpcattraryty, - name="Ax.{}".format(type_name)) - llrpcattrary.initializer = ll.Constant(llrpcattraryty, - llrpcattrs + [ll.Constant(llrpcattrty.as_pointer(), None)]) - llrpcattrary.global_constant = True - llrpcattrary.unnamed_addr = True - llrpcattrary.linkage = 'private' - - llobjectaryty = ll.ArrayType(llptr, len(llobjects[typ]) + 1) - llobjectary = ll.GlobalVariable(self.llmodule, llobjectaryty, - name="Ox.{}".format(type_name)) - llobjectary.initializer = ll.Constant(llobjectaryty, - llobjects[typ] + [ll.Constant(llptr, None)]) - llobjectary.linkage = 'private' - - lldesc = ll.GlobalVariable(self.llmodule, lldescty, - name="D.{}".format(type_name)) - lldesc.initializer = ll.Constant(lldescty, [ - llrpcattrary.bitcast(llrpcattrty.as_pointer().as_pointer()), - llobjectary.bitcast(llptr.as_pointer()) - ]) - lldesc.global_constant = True - lldesc.linkage = 'private' - lldescs.append(lldesc) - - llglobaldescty = ll.ArrayType(lldescty.as_pointer(), len(lldescs) + 1) - llglobaldesc = ll.GlobalVariable(self.llmodule, llglobaldescty, - name="typeinfo") - llglobaldesc.initializer = ll.Constant(llglobaldescty, - lldescs + [ll.Constant(lldescty.as_pointer(), None)]) - - def process_function(self, func): - try: - self.function_flags = func.flags - self.llfunction = self.map(func) - - if func.is_internal: - self.llfunction.linkage = 'private' - if func.is_cold: - self.llfunction.attributes.add('cold') - self.llfunction.attributes.add('noinline') - if 'inline' in func.flags: - self.llfunction.attributes.add('inlinehint') - if 'forceinline' in func.flags: - self.llfunction.attributes.add('alwaysinline') - - self.llfunction.attributes.add('uwtable') - self.llfunction.attributes.personality = self.llbuiltin("__artiq_personality") - - self.llbuilder = ll.IRBuilder() - llblock_map = {} - - # First, map arguments. - if self.has_sret(func.type): - llactualargs = self.llfunction.args[1:] - else: - llactualargs = self.llfunction.args - - for arg, llarg in zip(func.arguments, llactualargs): - llarg.name = arg.name - self.llmap[arg] = llarg - - # Second, create all basic blocks. - for block in func.basic_blocks: - llblock = self.llfunction.append_basic_block(block.name) - self.llmap[block] = llblock - - # Third, translate all instructions. - for block in func.basic_blocks: - self.llbuilder.position_at_end(self.llmap[block]) - for insn in block.instructions: - llinsn = getattr(self, "process_" + type(insn).__name__)(insn) - assert llinsn is not None - self.llmap[insn] = llinsn - - # There is no 1:1 correspondence between ARTIQ and LLVM - # basic blocks, because sometimes we expand a single ARTIQ - # instruction so that the result spans several LLVM basic - # blocks. This only really matters for phis, which are thus - # using a different map (the following one). - llblock_map[block] = self.llbuilder.basic_block - - # Fourth, add incoming values to phis. - for phi, llphi in self.phis: - for value, block in phi.incoming(): - llphi.add_incoming(self.map(value), llblock_map[block]) - finally: - self.function_flags = None - self.llfunction = None - self.llmap = {} - self.phis = [] - - def process_Phi(self, insn): - llinsn = self.llbuilder.phi(self.llty_of_type(insn.type), name=insn.name) - self.phis.append((insn, llinsn)) - return llinsn - - def llindex(self, index): - return ll.Constant(lli32, index) - - def process_Alloc(self, insn): - if ir.is_environment(insn.type): - return self.llbuilder.alloca(self.llty_of_type(insn.type, bare=True), - name=insn.name) - elif ir.is_option(insn.type): - if len(insn.operands) == 0: # empty - llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined) - return self.llbuilder.insert_value(llvalue, ll.Constant(lli1, False), 0, - name=insn.name) - elif len(insn.operands) == 1: # full - llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined) - llvalue = self.llbuilder.insert_value(llvalue, ll.Constant(lli1, True), 0) - return self.llbuilder.insert_value(llvalue, self.map(insn.operands[0]), 1, - name=insn.name) - else: - assert False - elif types._is_pointer(insn.type) or (builtins.is_listish(insn.type) - and not builtins.is_array(insn.type)): - llsize = self.map(insn.operands[0]) - lleltty = self.llty_of_type(builtins.get_iterable_elt(insn.type)) - llalloc = self.llbuilder.alloca(lleltty, size=llsize) - if types._is_pointer(insn.type): - return llalloc - llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined) - llvalue = self.llbuilder.insert_value(llvalue, llalloc, 0, name=insn.name) - llvalue = self.llbuilder.insert_value(llvalue, llsize, 1) - return llvalue - elif (not builtins.is_allocated(insn.type) or ir.is_keyword(insn.type) - or builtins.is_array(insn.type)): - llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined) - for index, elt in enumerate(insn.operands): - llvalue = self.llbuilder.insert_value(llvalue, self.map(elt), index) - llvalue.name = insn.name - return llvalue - elif types.is_constructor(insn.type): - return self.get_class(insn.type) - else: # catchall for exceptions and custom (allocated) classes - llalloc = self.llbuilder.alloca(self.llty_of_type(insn.type, bare=True)) - for index, operand in enumerate(insn.operands): - lloperand = self.map(operand) - llfieldptr = self.llbuilder.gep(llalloc, [self.llindex(0), self.llindex(index)], - inbounds=True) - self.llbuilder.store(lloperand, llfieldptr) - return llalloc - - def llptr_to_var(self, llenv, env_ty, var_name): - if var_name in env_ty.params: - var_index = list(env_ty.params.keys()).index(var_name) - return self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(var_index)], - inbounds=True) - else: - outer_index = list(env_ty.params.keys()).index("$outer") - llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)], - inbounds=True) - llouterenv = self.llbuilder.load(llptr) - llouterenv.set_metadata('invariant.load', self.empty_metadata) - llouterenv.set_metadata('nonnull', self.empty_metadata) - return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name) - - def mark_dereferenceable(self, load): - assert isinstance(load, ll.LoadInstr) and isinstance(load.type, ll.PointerType) - pointee_size, _ = self.abi_layout_info.get_size_align(load.type.pointee) - metadata = self.llmodule.add_metadata([ll.Constant(lli64, pointee_size)]) - load.set_metadata('dereferenceable', metadata) - - def process_GetLocal(self, insn): - env = insn.environment() - llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name) - llptr.name = "ptr.{}.{}".format(env.name, insn.var_name) - llvalue = self.llbuilder.load(llptr, name="val.{}.{}".format(env.name, insn.var_name)) - if isinstance(llvalue.type, ll.PointerType): - self.mark_dereferenceable(llvalue) - return llvalue - - def process_SetLocal(self, insn): - env = insn.environment() - llvalue = self.map(insn.value()) - if isinstance(llvalue.type, ll.VoidType): - # We store NoneType as {} but return it as void. So, bail out here. - return ll.Constant(ll.LiteralStructType([]), []) - llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name) - llptr.name = "ptr.{}.{}".format(env.name, insn.var_name) - if isinstance(llvalue, ll.Block): - llvalue = ll.BlockAddress(self.llfunction, llvalue) - if llptr.type.pointee != llvalue.type: - # The environment argument is an i8*, so that all closures can - # unify with each other regardless of environment type or size. - # We fixup the type on assignment into the "$outer" slot. - assert insn.var_name == '$outer' - llvalue = self.llbuilder.bitcast(llvalue, llptr.type.pointee) - return self.llbuilder.store(llvalue, llptr) - - def attr_index(self, typ, attr): - return list(typ.attributes.keys()).index(attr) - - def get_or_define_global(self, name, llty, llvalue=None): - if llvalue is None: - llvalue = ll.Constant(llty, ll.Undefined) - - if name in self.llmodule.globals: - llglobal = self.llmodule.get_global(name) - else: - llglobal = ll.GlobalVariable(self.llmodule, llty, name) - llglobal.linkage = "private" - if llvalue is not None: - llglobal.initializer = llvalue - return llglobal - - def get_class(self, typ): - assert types.is_constructor(typ) - llty = self.llty_of_type(typ).pointee - return self.get_or_define_global("C.{}".format(typ.name), llty) - - def get_global_closure_ptr(self, typ, attr): - closure_type = typ.attributes[attr] - assert types.is_constructor(typ) - assert types.is_function(closure_type) or types.is_rpc(closure_type) - if types.is_external_function(closure_type) or types.is_rpc(closure_type): - return None - - llty = self.llty_of_type(typ.attributes[attr]) - return self.get_or_define_global("F.{}.{}".format(typ.name, attr), llty) - - def get_global_closure(self, typ, attr): - llclosureptr = self.get_global_closure_ptr(typ, attr) - if llclosureptr is None: - return None - - # LLVM's GlobalOpt pass only considers for SROA the globals that - # are used only by GEPs, so we have to do this stupid hack. - llenvptr = self.llbuilder.gep(llclosureptr, [self.llindex(0), self.llindex(0)]) - llfunptr = self.llbuilder.gep(llclosureptr, [self.llindex(0), self.llindex(1)]) - return [llenvptr, llfunptr] - - def load_closure(self, typ, attr): - llclosureparts = self.get_global_closure(typ, attr) - if llclosureparts is None: - return ll.Constant(llunit, []) - - # See above. - llenvptr, llfunptr = llclosureparts - llenv = self.llbuilder.load(llenvptr) - llfun = self.llbuilder.load(llfunptr) - llclosure = ll.Constant(ll.LiteralStructType([llenv.type, llfun.type]), ll.Undefined) - llclosure = self.llbuilder.insert_value(llclosure, llenv, 0) - llclosure = self.llbuilder.insert_value(llclosure, llfun, 1) - return llclosure - - def store_closure(self, llclosure, typ, attr): - llclosureparts = self.get_global_closure(typ, attr) - assert llclosureparts is not None - - llenvptr, llfunptr = llclosureparts - llenv = self.llbuilder.extract_value(llclosure, 0) - llfun = self.llbuilder.extract_value(llclosure, 1) - self.llbuilder.store(llenv, llenvptr) - return self.llbuilder.store(llfun, llfunptr) - - def process_GetAttr(self, insn): - typ, attr = insn.object().type, insn.attr - if types.is_tuple(typ): - return self.llbuilder.extract_value(self.map(insn.object()), attr, - name=insn.name) - elif builtins.is_array(typ) or not builtins.is_allocated(typ): - return self.llbuilder.extract_value(self.map(insn.object()), - self.attr_index(typ, attr), - name=insn.name) - else: - if attr in typ.attributes: - index = self.attr_index(typ, attr) - obj = self.map(insn.object()) - elif attr in typ.constructor.attributes: - index = self.attr_index(typ.constructor, attr) - obj = self.get_class(typ.constructor) - else: - assert False - - if types.is_method(insn.type) and attr not in typ.attributes: - llfun = self.load_closure(typ.constructor, attr) - llfun.name = "met.{}.{}".format(typ.constructor.name, attr) - llself = self.map(insn.object()) - - llmethodty = self.llty_of_type(insn.type) - llmethod = ll.Constant(llmethodty, ll.Undefined) - llmethod = self.llbuilder.insert_value(llmethod, llfun, - self.attr_index(insn.type, '__func__')) - llmethod = self.llbuilder.insert_value(llmethod, llself, - self.attr_index(insn.type, '__self__')) - return llmethod - elif types.is_function(insn.type) and attr in typ.attributes and \ - types.is_constructor(typ): - llfun = self.load_closure(typ, attr) - llfun.name = "fun.{}".format(insn.name) - return llfun - else: - llptr = self.llbuilder.gep(obj, [self.llindex(0), self.llindex(index)], - inbounds=True, name="ptr.{}".format(insn.name)) - llvalue = self.llbuilder.load(llptr, name="val.{}".format(insn.name)) - if types.is_instance(typ) and attr in typ.constant_attributes: - llvalue.set_metadata('invariant.load', self.empty_metadata) - if isinstance(llvalue.type, ll.PointerType): - self.mark_dereferenceable(llvalue) - return llvalue - - def process_SetAttr(self, insn): - typ, attr = insn.object().type, insn.attr - assert builtins.is_allocated(typ) - - if attr in typ.attributes: - obj = self.map(insn.object()) - elif attr in typ.constructor.attributes: - typ = typ.constructor - obj = self.get_class(typ) - else: - assert False - - llvalue = self.map(insn.value()) - if types.is_function(insn.value().type) and attr in typ.attributes and \ - types.is_constructor(typ): - return self.store_closure(llvalue, typ, attr) - else: - llptr = self.llbuilder.gep(obj, [self.llindex(0), - self.llindex(self.attr_index(typ, attr))], - inbounds=True, name=insn.name) - return self.llbuilder.store(llvalue, llptr) - - def process_Offset(self, insn): - base, idx = insn.base(), insn.index() - llelts, llidx = map(self.map, (base, idx)) - if not types._is_pointer(base.type): - # This is list-ish. - llelts = self.llbuilder.extract_value(llelts, 0) - llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True) - return llelt - - def process_GetElem(self, insn): - llelt = self.process_Offset(insn) - llvalue = self.llbuilder.load(llelt) - if isinstance(llvalue.type, ll.PointerType): - self.mark_dereferenceable(llvalue) - return llvalue - - def process_SetElem(self, insn): - base, idx = insn.base(), insn.index() - llelts, llidx = map(self.map, (base, idx)) - if not types._is_pointer(base.type): - # This is list-ish. - llelts = self.llbuilder.extract_value(llelts, 0) - llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True) - return self.llbuilder.store(self.map(insn.value()), llelt) - - def process_Coerce(self, insn): - typ, value_typ = insn.type, insn.value().type - if typ == value_typ: - return self.map(insn.value()) - if builtins.is_int(typ) and builtins.is_float(value_typ): - return self.llbuilder.fptosi(self.map(insn.value()), self.llty_of_type(typ), - name=insn.name) - elif builtins.is_float(typ) and builtins.is_int(value_typ): - return self.llbuilder.sitofp(self.map(insn.value()), self.llty_of_type(typ), - name=insn.name) - elif builtins.is_int(typ) and builtins.is_int(value_typ): - if builtins.get_int_width(typ) > builtins.get_int_width(value_typ): - return self.llbuilder.sext(self.map(insn.value()), self.llty_of_type(typ), - name=insn.name) - else: # builtins.get_int_width(typ) <= builtins.get_int_width(value_typ): - return self.llbuilder.trunc(self.map(insn.value()), self.llty_of_type(typ), - name=insn.name) - else: - assert False - - def add_fast_math_flags(self, llvalue): - if 'fast-math' in self.function_flags: - llvalue.opname = llvalue.opname + ' fast' - - def process_Arith(self, insn): - if isinstance(insn.op, ast.Add): - if builtins.is_float(insn.type): - llvalue = self.llbuilder.fadd(self.map(insn.lhs()), self.map(insn.rhs()), - name=insn.name) - self.add_fast_math_flags(llvalue) - return llvalue - else: - return self.llbuilder.add(self.map(insn.lhs()), self.map(insn.rhs()), - name=insn.name) - elif isinstance(insn.op, ast.Sub): - if builtins.is_float(insn.type): - llvalue = self.llbuilder.fsub(self.map(insn.lhs()), self.map(insn.rhs()), - name=insn.name) - self.add_fast_math_flags(llvalue) - return llvalue - else: - return self.llbuilder.sub(self.map(insn.lhs()), self.map(insn.rhs()), - name=insn.name) - elif isinstance(insn.op, ast.Mult): - if builtins.is_float(insn.type): - llvalue = self.llbuilder.fmul(self.map(insn.lhs()), self.map(insn.rhs()), - name=insn.name) - self.add_fast_math_flags(llvalue) - return llvalue - else: - return self.llbuilder.mul(self.map(insn.lhs()), self.map(insn.rhs()), - name=insn.name) - elif isinstance(insn.op, ast.Div): - if builtins.is_float(insn.lhs().type): - llvalue = self.llbuilder.fdiv(self.map(insn.lhs()), self.map(insn.rhs()), - name=insn.name) - self.add_fast_math_flags(llvalue) - return llvalue - else: - lllhs = self.llbuilder.sitofp(self.map(insn.lhs()), self.llty_of_type(insn.type)) - llrhs = self.llbuilder.sitofp(self.map(insn.rhs()), self.llty_of_type(insn.type)) - llvalue = self.llbuilder.fdiv(lllhs, llrhs, - name=insn.name) - self.add_fast_math_flags(llvalue) - return llvalue - elif isinstance(insn.op, ast.FloorDiv): - if builtins.is_float(insn.type): - llvalue = self.llbuilder.fdiv(self.map(insn.lhs()), self.map(insn.rhs())) - self.add_fast_math_flags(llvalue) - return self.llbuilder.call(self.llbuiltin("llvm.floor.f64"), [llvalue], - name=insn.name) - else: - return self.llbuilder.sdiv(self.map(insn.lhs()), self.map(insn.rhs()), - name=insn.name) - elif isinstance(insn.op, ast.Mod): - lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs())) - if builtins.is_float(insn.type): - intrinsic = "__py_moddf3" - elif builtins.is_int32(insn.type): - intrinsic = "__py_modsi3" - elif builtins.is_int64(insn.type): - intrinsic = "__py_moddi3" - return self.llbuilder.call(self.llbuiltin(intrinsic), [lllhs, llrhs], - name=insn.name) - elif isinstance(insn.op, ast.Pow): - if builtins.is_float(insn.type): - return self.llbuilder.call(self.llbuiltin("llvm.pow.f64"), - [self.map(insn.lhs()), self.map(insn.rhs())], - name=insn.name) - else: - lllhs = self.llbuilder.sitofp(self.map(insn.lhs()), lldouble) - llrhs = self.llbuilder.trunc(self.map(insn.rhs()), lli32) - llvalue = self.llbuilder.call(self.llbuiltin("llvm.powi.f64"), [lllhs, llrhs]) - return self.llbuilder.fptosi(llvalue, self.llty_of_type(insn.type), - name=insn.name) - elif isinstance(insn.op, ast.LShift): - lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs())) - llrhs_max = ll.Constant(llrhs.type, builtins.get_int_width(insn.lhs().type)) - llrhs_overflow = self.llbuilder.icmp_signed('>=', llrhs, llrhs_max) - llvalue_zero = ll.Constant(lllhs.type, 0) - llvalue = self.llbuilder.shl(lllhs, llrhs) - return self.llbuilder.select(llrhs_overflow, llvalue_zero, llvalue, - name=insn.name) - elif isinstance(insn.op, ast.RShift): - lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs())) - llrhs_max = ll.Constant(llrhs.type, builtins.get_int_width(insn.lhs().type) - 1) - llrhs_overflow = self.llbuilder.icmp_signed('>', llrhs, llrhs_max) - llvalue = self.llbuilder.ashr(lllhs, llrhs) - llvalue_max = self.llbuilder.ashr(lllhs, llrhs_max) # preserve sign bit - return self.llbuilder.select(llrhs_overflow, llvalue_max, llvalue, - name=insn.name) - elif isinstance(insn.op, ast.BitAnd): - return self.llbuilder.and_(self.map(insn.lhs()), self.map(insn.rhs()), - name=insn.name) - elif isinstance(insn.op, ast.BitOr): - return self.llbuilder.or_(self.map(insn.lhs()), self.map(insn.rhs()), - name=insn.name) - elif isinstance(insn.op, ast.BitXor): - return self.llbuilder.xor(self.map(insn.lhs()), self.map(insn.rhs()), - name=insn.name) - else: - assert False - - def process_Compare(self, insn): - if isinstance(insn.op, (ast.Eq, ast.Is)): - op = '==' - elif isinstance(insn.op, (ast.NotEq, ast.IsNot)): - op = '!=' - elif isinstance(insn.op, ast.Gt): - op = '>' - elif isinstance(insn.op, ast.GtE): - op = '>=' - elif isinstance(insn.op, ast.Lt): - op = '<' - elif isinstance(insn.op, ast.LtE): - op = '<=' - else: - assert False - - lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs())) - assert lllhs.type == llrhs.type - - if isinstance(lllhs.type, ll.IntType): - return self.llbuilder.icmp_signed(op, lllhs, llrhs, - name=insn.name) - elif isinstance(lllhs.type, ll.PointerType): - return self.llbuilder.icmp_unsigned(op, lllhs, llrhs, - name=insn.name) - elif isinstance(lllhs.type, ll.DoubleType): - llresult = self.llbuilder.fcmp_ordered(op, lllhs, llrhs, - name=insn.name) - self.add_fast_math_flags(llresult) - return llresult - elif isinstance(lllhs.type, ll.LiteralStructType): - # Compare aggregates (such as lists or ranges) element-by-element. - llvalue = ll.Constant(lli1, True) - for index in range(len(lllhs.type.elements)): - lllhselt = self.llbuilder.extract_value(lllhs, index) - llrhselt = self.llbuilder.extract_value(llrhs, index) - llresult = self.llbuilder.icmp_unsigned('==', lllhselt, llrhselt) - llvalue = self.llbuilder.select(llresult, llvalue, - ll.Constant(lli1, False)) - return self.llbuilder.icmp_unsigned(op, llvalue, ll.Constant(lli1, True), - name=insn.name) - else: - print(lllhs, llrhs) - assert False - - def process_Builtin(self, insn): - if insn.op == "nop": - return self.llbuilder.call(self.llbuiltin("llvm.donothing"), []) - elif insn.op == "is_some": - lloptarg = self.map(insn.operands[0]) - return self.llbuilder.extract_value(lloptarg, 0, - name=insn.name) - elif insn.op == "unwrap": - lloptarg = self.map(insn.operands[0]) - return self.llbuilder.extract_value(lloptarg, 1, - name=insn.name) - elif insn.op == "unwrap_or": - lloptarg, lldefault = map(self.map, insn.operands) - llhas_arg = self.llbuilder.extract_value(lloptarg, 0, name="opt.has") - llarg = self.llbuilder.extract_value(lloptarg, 1, name="opt.val") - return self.llbuilder.select(llhas_arg, llarg, lldefault, - name=insn.name) - elif insn.op == "round": - llarg = self.map(insn.operands[0]) - llvalue = self.llbuilder.call(self.llbuiltin("llvm.round.f64"), [llarg]) - return self.llbuilder.fptosi(llvalue, self.llty_of_type(insn.type), - name=insn.name) - elif insn.op == "globalenv": - def get_outer(llenv, env_ty): - if "$outer" in env_ty.params: - outer_index = list(env_ty.params.keys()).index("$outer") - llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)], - inbounds=True) - llouterenv = self.llbuilder.load(llptr) - llouterenv.set_metadata('invariant.load', self.empty_metadata) - llouterenv.set_metadata('nonnull', self.empty_metadata) - return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name) - else: - return llenv - - env, = insn.operands - return get_outer(self.map(env), env.type) - elif insn.op == "len": - collection, = insn.operands - if builtins.is_array(collection.type): - # Return length of outermost dimension. - shape = self.llbuilder.extract_value(self.map(collection), - self.attr_index(collection.type, "shape")) - return self.llbuilder.extract_value(shape, 0) - return self.llbuilder.extract_value(self.map(collection), 1) - elif insn.op in ("printf", "rtio_log"): - # We only get integers, floats, pointers and strings here. - lloperands = [] - for i, operand in enumerate(insn.operands): - lloperand = self.map(operand) - if i == 0 and (insn.op == "printf" or insn.op == "rtio_log"): - lloperands.append(self.llbuilder.extract_value(lloperand, 0)) - elif builtins.is_str(operand.type) or builtins.is_bytes(operand.type): - lloperands.append(self.llbuilder.extract_value(lloperand, 1)) - lloperands.append(self.llbuilder.extract_value(lloperand, 0)) - else: - lloperands.append(lloperand) - func_name = self.target.print_function if insn.op == "printf" else insn.op - return self.llbuilder.call(self.llbuiltin(func_name), lloperands, - name=insn.name) - elif insn.op == "exncast": - # This is an identity cast at LLVM IR level. - return self.map(insn.operands[0]) - elif insn.op == "now_mu": - if self.target.now_pinning: - # Word swap now.old as CPU is little endian - # Most significant word is stored in lower address (see generated csr.rs) - llnow_raw = self.llbuilder.load(self.llbuiltin("now"), name=insn.name) - llnow_lo = self.llbuilder.shl(llnow_raw, ll.Constant(lli64, 32)) - llnow_hi = self.llbuilder.lshr(llnow_raw, ll.Constant(lli64, 32)) - return self.llbuilder.or_(llnow_lo, llnow_hi) - else: - return self.llbuilder.call(self.llbuiltin("now_mu"), []) - elif insn.op == "at_mu": - time, = insn.operands - lltime = self.map(time) - if self.target.now_pinning: - lltime_hi = self.llbuilder.trunc(self.llbuilder.lshr(lltime, ll.Constant(lli64, 32)), lli32) - lltime_lo = self.llbuilder.trunc(lltime, lli32) - llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer()) - llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) - llstore_hi = self.llbuilder.store_atomic(lltime_hi, llnow_hiptr, ordering="seq_cst", align=4) - llstore_lo = self.llbuilder.store_atomic(lltime_lo, llnow_loptr, ordering="seq_cst", align=4) - return llstore_lo - else: - return self.llbuilder.call(self.llbuiltin("at_mu"), [lltime]) - elif insn.op == "delay_mu": - interval, = insn.operands - llinterval = self.map(interval) - if self.target.now_pinning: - llnowptr = self.llbuiltin("now") - llnow = self.llbuilder.load(llnowptr, name="now.old") - - # Word swap now.old as CPU is little endian - # Most significant word is stored in lower address (see generated csr.rs) - llnow_lo = self.llbuilder.shl(llnow, ll.Constant(lli64, 32)) - llnow_hi = self.llbuilder.lshr(llnow, ll.Constant(lli64, 32)) - llnow = self.llbuilder.or_(llnow_lo, llnow_hi) - - lladjusted = self.llbuilder.add(llnow, llinterval, name="now.new") - lladjusted_hi = self.llbuilder.trunc(self.llbuilder.lshr(lladjusted, ll.Constant(lli64, 32)), lli32) - lladjusted_lo = self.llbuilder.trunc(lladjusted, lli32) - llnow_hiptr = self.llbuilder.bitcast(llnowptr, lli32.as_pointer()) - llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) - llstore_hi = self.llbuilder.store_atomic(lladjusted_hi, llnow_hiptr, ordering="seq_cst", align=4) - llstore_lo = self.llbuilder.store_atomic(lladjusted_lo, llnow_loptr, ordering="seq_cst", align=4) - return llstore_lo - else: - return self.llbuilder.call(self.llbuiltin("delay_mu"), [llinterval]) - else: - assert False - - def process_Closure(self, insn): - llenv = self.map(insn.environment()) - llenv = self.llbuilder.bitcast(llenv, llptr) - llfun = self.map(insn.target_function) - llvalue = ll.Constant(self.llty_of_type(insn.target_function.type), ll.Undefined) - llvalue = self.llbuilder.insert_value(llvalue, llenv, 0) - llvalue = self.llbuilder.insert_value(llvalue, llfun, 1, name=insn.name) - return llvalue - - def _prepare_closure_call(self, insn): - llargs = [self.map(arg) for arg in insn.arguments()] - llclosure = self.map(insn.target_function()) - if insn.static_target_function is None: - if isinstance(llclosure, ll.Constant): - name = "fun.{}".format(llclosure.constant[1].name) - else: - name = "fun.{}".format(llclosure.name) - llfun = self.llbuilder.extract_value(llclosure, 1, name=name) - else: - llfun = self.map(insn.static_target_function) - llenv = self.llbuilder.extract_value(llclosure, 0, name="env.fun") - return llfun, [llenv] + list(llargs) - - def _prepare_ffi_call(self, insn): - llargs = [] - byvals = [] - for i, arg in enumerate(insn.arguments()): - llarg = self.map(arg) - if isinstance(llarg.type, (ll.LiteralStructType, ll.IdentifiedStructType)): - llslot = self.llbuilder.alloca(llarg.type) - self.llbuilder.store(llarg, llslot) - llargs.append(llslot) - byvals.append(i) - else: - llargs.append(llarg) - - llfunname = insn.target_function().type.name - llfun = self.llmodule.globals.get(llfunname) - if llfun is None: - llretty = self.llty_of_type(insn.type, for_return=True) - if self.needs_sret(llretty): - llfunty = ll.FunctionType(llvoid, [llretty.as_pointer()] + - [llarg.type for llarg in llargs]) - else: - llfunty = ll.FunctionType(llretty, [llarg.type for llarg in llargs]) - - llfun = ll.Function(self.llmodule, llfunty, - insn.target_function().type.name) - if self.needs_sret(llretty): - llfun.args[0].add_attribute('sret') - byvals = [i + 1 for i in byvals] - for i in byvals: - llfun.args[i].add_attribute('byval') - if 'nounwind' in insn.target_function().type.flags: - llfun.attributes.add('nounwind') - if 'nowrite' in insn.target_function().type.flags: - llfun.attributes.add('inaccessiblememonly') - - return llfun, list(llargs) - - def _build_rpc(self, fun_loc, fun_type, args, llnormalblock, llunwindblock): - llservice = ll.Constant(lli32, fun_type.service) - - tag = b"" - - for arg in args: - def arg_error_handler(typ): - printer = types.TypePrinter() - note = diagnostic.Diagnostic("note", - "value of type {type}", - {"type": printer.name(typ)}, - arg.loc) - diag = diagnostic.Diagnostic("error", - "type {type} is not supported in remote procedure calls", - {"type": printer.name(arg.type)}, - arg.loc, notes=[note]) - self.engine.process(diag) - tag += ir.rpc_tag(arg.type, arg_error_handler) - tag += b":" - - def ret_error_handler(typ): - printer = types.TypePrinter() - note = diagnostic.Diagnostic("note", - "value of type {type}", - {"type": printer.name(typ)}, - fun_loc) - diag = diagnostic.Diagnostic("error", - "return type {type} is not supported in remote procedure calls", - {"type": printer.name(fun_type.ret)}, - fun_loc, notes=[note]) - self.engine.process(diag) - tag += ir.rpc_tag(fun_type.ret, ret_error_handler) - - lltag = self.llconst_of_const(ir.Constant(tag, builtins.TStr())) - lltagptr = self.llbuilder.alloca(lltag.type) - self.llbuilder.store(lltag, lltagptr) - - llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [], - name="rpc.stack") - - llargs = self.llbuilder.alloca(llptr, ll.Constant(lli32, len(args)), - name="rpc.args") - for index, arg in enumerate(args): - if builtins.is_none(arg.type): - llargslot = self.llbuilder.alloca(llunit, - name="rpc.arg{}".format(index)) - else: - llarg = self.map(arg) - llargslot = self.llbuilder.alloca(llarg.type, - name="rpc.arg{}".format(index)) - self.llbuilder.store(llarg, llargslot) - llargslot = self.llbuilder.bitcast(llargslot, llptr) - - llargptr = self.llbuilder.gep(llargs, [ll.Constant(lli32, index)]) - self.llbuilder.store(llargslot, llargptr) - - if fun_type.is_async: - self.llbuilder.call(self.llbuiltin("rpc_send_async"), - [llservice, lltagptr, llargs]) - else: - self.llbuilder.call(self.llbuiltin("rpc_send"), - [llservice, lltagptr, llargs]) - - # Don't waste stack space on saved arguments. - self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr]) - - if fun_type.is_async: - # If this RPC is called using an `invoke` ARTIQ IR instruction, there will be - # no other instructions in this basic block. Since this RPC is async, it cannot - # possibly raise an exception, so add an explicit jump to the normal successor. - if llunwindblock: - self.llbuilder.branch(llnormalblock) - - return ll.Undefined - - # T result = { - # void *ret_ptr = alloca(sizeof(T)); - # void *ptr = ret_ptr; - # loop: int size = rpc_recv(ptr); - # // Non-zero: Provide `size` bytes of extra storage for variable-length data. - # if(size) { ptr = alloca(size); goto loop; } - # else *(T*)ret_ptr - # } - llprehead = self.llbuilder.basic_block - llhead = self.llbuilder.append_basic_block(name="rpc.head") - if llunwindblock: - llheadu = self.llbuilder.append_basic_block(name="rpc.head.unwind") - llalloc = self.llbuilder.append_basic_block(name="rpc.continue") - lltail = self.llbuilder.append_basic_block(name="rpc.tail") - - llretty = self.llty_of_type(fun_type.ret) - llslot = self.llbuilder.alloca(llretty, name="rpc.ret.alloc") - llslotgen = self.llbuilder.bitcast(llslot, llptr, name="rpc.ret.ptr") - self.llbuilder.branch(llhead) - - self.llbuilder.position_at_end(llhead) - llphi = self.llbuilder.phi(llslotgen.type, name="rpc.ptr") - llphi.add_incoming(llslotgen, llprehead) - if llunwindblock: - llsize = self.llbuilder.invoke(self.llbuiltin("rpc_recv"), [llphi], - llheadu, llunwindblock, - name="rpc.size.next") - self.llbuilder.position_at_end(llheadu) - else: - llsize = self.llbuilder.call(self.llbuiltin("rpc_recv"), [llphi], - name="rpc.size.next") - lldone = self.llbuilder.icmp_unsigned('==', llsize, ll.Constant(llsize.type, 0), - name="rpc.done") - self.llbuilder.cbranch(lldone, lltail, llalloc) - - self.llbuilder.position_at_end(llalloc) - llalloca = self.llbuilder.alloca(lli8, llsize, name="rpc.alloc") - llalloca.align = 4 # maximum alignment required by OR1K ABI - llphi.add_incoming(llalloca, llalloc) - self.llbuilder.branch(llhead) - - self.llbuilder.position_at_end(lltail) - llret = self.llbuilder.load(llslot, name="rpc.ret") - if not fun_type.ret.fold(False, lambda r, t: r or builtins.is_allocated(t)): - # We didn't allocate anything except the slot for the value itself. - # Don't waste stack space. - self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr]) - if llnormalblock: - self.llbuilder.branch(llnormalblock) - return llret - - def process_Call(self, insn): - functiontyp = insn.target_function().type - if types.is_rpc(functiontyp): - return self._build_rpc(insn.target_function().loc, - functiontyp, - insn.arguments(), - llnormalblock=None, llunwindblock=None) - elif types.is_external_function(functiontyp): - llfun, llargs = self._prepare_ffi_call(insn) - else: - llfun, llargs = self._prepare_closure_call(insn) - - if self.has_sret(functiontyp): - llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), []) - - llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee) - llcall = self.llbuilder.call(llfun, [llresultslot] + llargs) - llresult = self.llbuilder.load(llresultslot) - - self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr]) - else: - llcall = llresult = self.llbuilder.call(llfun, llargs, name=insn.name) - - if isinstance(llresult.type, ll.VoidType): - # We have NoneType-returning functions return void, but None is - # {} elsewhere. - llresult = ll.Constant(llunit, []) - - return llresult - - def process_Invoke(self, insn): - functiontyp = insn.target_function().type - llnormalblock = self.map(insn.normal_target()) - llunwindblock = self.map(insn.exception_target()) - if types.is_rpc(functiontyp): - return self._build_rpc(insn.target_function().loc, - functiontyp, - insn.arguments(), - llnormalblock, llunwindblock) - elif types.is_external_function(functiontyp): - llfun, llargs = self._prepare_ffi_call(insn) - else: - llfun, llargs = self._prepare_closure_call(insn) - - if self.has_sret(functiontyp): - llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), []) - - llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee) - llcall = self.llbuilder.invoke(llfun, [llresultslot] + llargs, - llnormalblock, llunwindblock, name=insn.name) - - self.llbuilder.position_at_start(llnormalblock) - llresult = self.llbuilder.load(llresultslot) - - self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr]) - else: - llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock, - name=insn.name) - llresult = llcall - - # The !tbaa metadata is not legal to use with the invoke instruction, - # so unlike process_Call, we do not set it here. - - return llresult - - def _quote_listish_to_llglobal(self, value, elt_type, path, kind_name): - fail_msg = "at " + ".".join(path()) - if len(value) > 0: - if builtins.is_int(elt_type): - int_typ = (int, numpy.int32, numpy.int64) - for v in value: - assert isinstance(v, int_typ), fail_msg - llty = self.llty_of_type(elt_type) - llelts = [ll.Constant(llty, int(v)) for v in value] - elif builtins.is_float(elt_type): - for v in value: - assert isinstance(v, float), fail_msg - llty = self.llty_of_type(elt_type) - llelts = [ll.Constant(llty, v) for v in value] - else: - llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)]) - for i in range(len(value))] - else: - llelts = [] - lleltsary = ll.Constant(ll.ArrayType(self.llty_of_type(elt_type), len(llelts)), - list(llelts)) - name = self.llmodule.scope.deduplicate("quoted.{}".format(kind_name)) - llglobal = ll.GlobalVariable(self.llmodule, lleltsary.type, name) - llglobal.initializer = lleltsary - llglobal.linkage = "private" - return llglobal.bitcast(lleltsary.type.element.as_pointer()) - - def _quote_attributes(self, value, typ, path, value_id, llty): - llglobal = None - llfields = [] - emit_as_constant = True - for attr in typ.attributes: - if attr == "__objectid__": - objectid = self.embedding_map.store_object(value) - llfields.append(ll.Constant(lli32, objectid)) - - assert llglobal is None - if types.is_constructor(typ): - llglobal = self.get_class(typ) - else: - llglobal = ll.GlobalVariable(self.llmodule, llty.pointee, - name="O.{}".format(objectid)) - - self.llobject_map[value_id] = llglobal - else: - attrvalue = getattr(value, attr) - is_class_function = (types.is_constructor(typ) and - types.is_function(typ.attributes[attr]) and - not types.is_external_function(typ.attributes[attr])) - if is_class_function: - attrvalue = self.embedding_map.specialize_function(typ.instance, attrvalue) - if not (types.is_instance(typ) and attr in typ.constant_attributes): - emit_as_constant = False - llattrvalue = self._quote(attrvalue, typ.attributes[attr], - lambda: path() + [attr]) - llfields.append(llattrvalue) - if is_class_function: - llclosureptr = self.get_global_closure_ptr(typ, attr) - llclosureptr.initializer = llattrvalue - - llglobal.global_constant = emit_as_constant - llglobal.initializer = ll.Constant(llty.pointee, llfields) - llglobal.linkage = "private" - return llglobal - - def _quote(self, value, typ, path): - value_id = id(value) - if value_id in self.llobject_map: - return self.llobject_map[value_id] - llty = self.llty_of_type(typ) - - fail_msg = self.quote_fail_msg - if fail_msg == None: - self.quote_fail_msg = fail_msg = "at " + ".".join(path()) - - if types.is_constructor(typ) or types.is_instance(typ): - if types.is_instance(typ): - # Make sure the class functions are quoted, as this has the side effect of - # initializing the global closures. - self._quote(type(value), typ.constructor, - lambda: path() + ['__class__']) - return self._quote_attributes(value, typ, path, value_id, llty) - elif types.is_module(typ): - return self._quote_attributes(value, typ, path, value_id, llty) - elif builtins.is_none(typ): - assert value is None, fail_msg - return ll.Constant.literal_struct([]) - elif builtins.is_bool(typ): - assert value in (True, False), fail_msg - # Explicitly cast to bool to handle numpy.bool_. - return ll.Constant(llty, bool(value)) - elif builtins.is_int(typ): - assert isinstance(value, (int, numpy.int32, numpy.int64)), fail_msg - return ll.Constant(llty, int(value)) - elif builtins.is_float(typ): - assert isinstance(value, float), fail_msg - return ll.Constant(llty, value) - elif builtins.is_str(typ) or builtins.is_bytes(typ) or builtins.is_bytearray(typ): - assert isinstance(value, (str, bytes, bytearray)), fail_msg - if isinstance(value, str): - as_bytes = value.encode("utf-8") - else: - as_bytes = value - - llstr = self.llstr_of_str(as_bytes) - llconst = ll.Constant(llty, [llstr, ll.Constant(lli32, len(as_bytes))]) - return llconst - elif builtins.is_array(typ): - assert isinstance(value, numpy.ndarray), fail_msg - typ = typ.find() - assert len(value.shape) == typ["num_dims"].find().value - flattened = value.reshape((-1,)) - lleltsptr = self._quote_listish_to_llglobal(flattened, typ["elt"], path, "array") - llshape = ll.Constant.literal_struct([ll.Constant(lli32, s) for s in value.shape]) - return ll.Constant(llty, [lleltsptr, llshape]) - elif builtins.is_listish(typ): - assert isinstance(value, (list, numpy.ndarray)), fail_msg - elt_type = builtins.get_iterable_elt(typ) - lleltsptr = self._quote_listish_to_llglobal(value, elt_type, path, typ.find().name) - llconst = ll.Constant(llty, [lleltsptr, ll.Constant(lli32, len(value))]) - return llconst - elif types.is_tuple(typ): - assert isinstance(value, tuple), fail_msg - llelts = [self._quote(v, t, lambda: path() + [str(i)]) - for i, (v, t) in enumerate(zip(value, typ.elts))] - return ll.Constant(llty, llelts) - elif types.is_rpc(typ) or types.is_external_function(typ) or types.is_builtin_function(typ): - # RPC, C and builtin functions have no runtime representation. - return ll.Constant(llty, ll.Undefined) - elif types.is_function(typ): - try: - func = self.embedding_map.retrieve_function(value) - except KeyError: - # If a class function was embedded directly (e.g. by a `C.f(...)` call), - # but it also appears in a class hierarchy, we might need to fall back - # to the non-specialized one, since direct invocations do not cause - # monomorphization. - assert isinstance(value, SpecializedFunction) - func = self.embedding_map.retrieve_function(value.host_function) - return self.get_function_with_undef_env(typ.find(), func) - elif types.is_method(typ): - llclosure = self._quote(value.__func__, types.get_method_function(typ), - lambda: path() + ['__func__']) - llself = self._quote(value.__self__, types.get_method_self(typ), - lambda: path() + ['__self__']) - return ll.Constant(llty, [llclosure, llself]) - else: - print(typ) - assert False, fail_msg - - def process_Quote(self, insn): - assert self.embedding_map is not None - return self._quote(insn.value, insn.type, lambda: [repr(insn.value)]) - - def process_Select(self, insn): - return self.llbuilder.select(self.map(insn.condition()), - self.map(insn.if_true()), self.map(insn.if_false())) - - def process_Branch(self, insn): - return self.llbuilder.branch(self.map(insn.target())) - - process_Delay = process_Branch - - def process_BranchIf(self, insn): - return self.llbuilder.cbranch(self.map(insn.condition()), - self.map(insn.if_true()), self.map(insn.if_false())) - - process_Loop = process_BranchIf - - def process_IndirectBranch(self, insn): - llinsn = self.llbuilder.branch_indirect(self.map(insn.target())) - for dest in insn.destinations(): - llinsn.add_destination(self.map(dest)) - return llinsn - - def process_Return(self, insn): - if builtins.is_none(insn.value().type): - return self.llbuilder.ret_void() - else: - llvalue = self.map(insn.value()) - if self.needs_sret(llvalue.type): - self.llbuilder.store(llvalue, self.llfunction.args[0]) - return self.llbuilder.ret_void() - else: - return self.llbuilder.ret(llvalue) - - def process_Unreachable(self, insn): - return self.llbuilder.unreachable() - - def _gen_raise(self, insn, func, args): - if insn.exception_target() is not None: - llnormalblock = self.llfunction.append_basic_block("unreachable") - llnormalblock.terminator = ll.Unreachable(llnormalblock) - llnormalblock.instructions.append(llnormalblock.terminator) - - llunwindblock = self.map(insn.exception_target()) - llinsn = self.llbuilder.invoke(func, args, - llnormalblock, llunwindblock, - name=insn.name) - else: - llinsn = self.llbuilder.call(func, args, - name=insn.name) - self.llbuilder.unreachable() - llinsn.attributes.add('noreturn') - return llinsn - - def process_Raise(self, insn): - llexn = self.map(insn.value()) - return self._gen_raise(insn, self.llbuiltin("__artiq_raise"), [llexn]) - - def process_Reraise(self, insn): - return self._gen_raise(insn, self.llbuiltin("__artiq_reraise"), []) - - def process_LandingPad(self, insn): - # Layout on return from landing pad: {%_Unwind_Exception*, %Exception*} - lllandingpadty = ll.LiteralStructType([llptr, llptr]) - lllandingpad = self.llbuilder.landingpad(lllandingpadty, cleanup=True) - llrawexn = self.llbuilder.extract_value(lllandingpad, 1) - llexn = self.llbuilder.bitcast(llrawexn, self.llty_of_type(insn.type)) - llexnnameptr = self.llbuilder.gep(llexn, [self.llindex(0), self.llindex(0)], - inbounds=True) - llexnname = self.llbuilder.load(llexnnameptr) - - for target, typ in insn.clauses(): - if typ is None: - exnname = "" # see the comment in ksupport/eh.rs - else: - exnname = "{}:{}".format(typ.id, typ.name) - - llclauseexnname = self.llconst_of_const( - ir.Constant(exnname, builtins.TStr())) - llclauseexnnameptr = self.llmodule.globals.get("exn.{}".format(exnname)) - if llclauseexnnameptr is None: - llclauseexnnameptr = ll.GlobalVariable(self.llmodule, llclauseexnname.type, - name="exn.{}".format(exnname)) - llclauseexnnameptr.global_constant = True - llclauseexnnameptr.initializer = llclauseexnname - llclauseexnnameptr.linkage = "private" - llclauseexnnameptr.unnamed_addr = True - lllandingpad.add_clause(ll.CatchClause(llclauseexnnameptr)) - - if typ is None: - self.llbuilder.branch(self.map(target)) - else: - llexnlen = self.llbuilder.extract_value(llexnname, 1) - llclauseexnlen = self.llbuilder.extract_value(llclauseexnname, 1) - llmatchinglen = self.llbuilder.icmp_unsigned('==', llexnlen, llclauseexnlen) - with self.llbuilder.if_then(llmatchinglen): - llexnptr = self.llbuilder.extract_value(llexnname, 0) - llclauseexnptr = self.llbuilder.extract_value(llclauseexnname, 0) - llcomparedata = self.llbuilder.call(self.llbuiltin("memcmp"), - [llexnptr, llclauseexnptr, llexnlen]) - llmatchingdata = self.llbuilder.icmp_unsigned('==', llcomparedata, - ll.Constant(lli32, 0)) - with self.llbuilder.if_then(llmatchingdata): - self.llbuilder.branch(self.map(target)) - - if self.llbuilder.basic_block.terminator is None: - self.llbuilder.branch(self.map(insn.cleanup())) - - return llexn diff --git a/artiq/compiler/transforms/local_demoter.py b/artiq/compiler/transforms/local_demoter.py deleted file mode 100644 index 4701e7a7c..000000000 --- a/artiq/compiler/transforms/local_demoter.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -:class:`LocalDemoter` is a constant propagation transform: -it replaces reads of any local variable with only one write -in a function without closures with the value that was written. - -:class:`LocalAccessValidator` must be run before this transform -to ensure that the transformation it performs is sound. -""" - -from collections import defaultdict -from .. import ir - -class LocalDemoter: - def process(self, functions): - for func in functions: - self.process_function(func) - - def process_function(self, func): - env_safe = {} - env_gets = defaultdict(lambda: set()) - env_sets = defaultdict(lambda: set()) - - for insn in func.instructions(): - if isinstance(insn, (ir.GetLocal, ir.SetLocal)): - if "$" in insn.var_name: - continue - - env = insn.environment() - - if env not in env_safe: - for use in env.uses: - if not isinstance(use, (ir.GetLocal, ir.SetLocal)): - env_safe[env] = False - break - else: - env_safe[env] = True - - if not env_safe[env]: - continue - - if isinstance(insn, ir.SetLocal): - env_sets[(env, insn.var_name)].add(insn) - else: - env_gets[(env, insn.var_name)].add(insn) - - for (env, var_name) in env_sets: - if len(env_sets[(env, var_name)]) == 1: - set_insn = next(iter(env_sets[(env, var_name)])) - for get_insn in env_gets[(env, var_name)]: - get_insn.replace_all_uses_with(set_insn.value()) - get_insn.erase() diff --git a/artiq/compiler/transforms/typedtree_printer.py b/artiq/compiler/transforms/typedtree_printer.py deleted file mode 100644 index e0c296f42..000000000 --- a/artiq/compiler/transforms/typedtree_printer.py +++ /dev/null @@ -1,89 +0,0 @@ -""" -:class:`TypedtreePrinter` prints a human-readable representation of typedtrees. -""" - -from pythonparser import algorithm, ast -from .. import types, asttyped - -class TypedtreePrinter(algorithm.Visitor): - def __init__(self): - self.str = None - self.level = None - self.last_nl = None - self.type_printer = None - - def print(self, node): - try: - self.str = "" - self.level = 0 - self.last_nl = 0 - self.type_printer = types.TypePrinter() - self.visit(node) - self._nl() - return self.str - finally: - self.str = None - self.level = None - self.last_nl = 0 - self.type_printer = None - - def _nl(self): - # self.str += "·" - if len(self.str) != self.last_nl: - self.str += "\n" + (" " * self.level) - self.last_nl = len(self.str) - - def _indent(self): - self.level += 1 - self._nl() - - def _dedent(self): - self._nl() - self.level -= 1 - self.str = self.str[:-2] - self.last_nl -= 2 - - def visit(self, obj): - if isinstance(obj, ast.AST): - attrs = set(obj._fields) - {'ctx'} - if isinstance(obj, asttyped.commontyped): - attrs.update(set(obj._types)) - - for attr in set(attrs): - if not getattr(obj, attr): - attrs.remove(attr) # omit falsey stuff - - self.str += obj.__class__.__name__ + "(" - if len(attrs) > 1: - self._indent() - - for attr in attrs: - if len(attrs) > 1: - self._nl() - self.str += attr + "=" - self.visit(getattr(obj, attr)) - if len(attrs) > 1: - self._nl() - - if len(attrs) > 1: - self._dedent() - self.str += ")" - elif isinstance(obj, types.Type): - self.str += self.type_printer.name(obj, max_depth=0) - elif isinstance(obj, list): - self.str += "[" - if len(obj) > 1: - self._indent() - - for elem in obj: - if len(obj) > 1: - self._nl() - self.visit(elem) - if len(obj) > 1: - self._nl() - - if len(obj) > 1: - self._dedent() - self.str += "]" - else: - self.str += repr(obj) diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py deleted file mode 100644 index 1d9336b4d..000000000 --- a/artiq/compiler/types.py +++ /dev/null @@ -1,839 +0,0 @@ -""" -The :mod:`types` module contains the classes describing the types -in :mod:`asttyped`. -""" - -import builtins -import string -from collections import OrderedDict -from . import iodelay - - -class UnificationError(Exception): - def __init__(self, typea, typeb): - self.typea, self.typeb = typea, typeb - - -def genalnum(): - ident = ["a"] - while True: - yield "".join(ident) - pos = len(ident) - 1 - while pos >= 0: - cur_n = string.ascii_lowercase.index(ident[pos]) - if cur_n < 25: - ident[pos] = string.ascii_lowercase[cur_n + 1] - break - else: - ident[pos] = "a" - pos -= 1 - if pos < 0: - ident = ["a"] + ident - -def _freeze(dict_): - return tuple((key, dict_[key]) for key in dict_) - -def _map_find(elts): - if isinstance(elts, list): - return [x.find() for x in elts] - elif isinstance(elts, dict): - return {k: elts[k].find() for k in elts} - else: - assert False - - -class Type(object): - def __str__(self): - return TypePrinter().name(self) - -class TVar(Type): - """ - A type variable. - - In effect, the classic union-find data structure is intrusively - folded into this class. - """ - - def __init__(self): - self.parent = self - self.rank = 0 - - def find(self): - parent = self.parent - if parent is self: - return self - else: - # The recursive find() invocation is turned into a loop - # because paths resulting from unification of large arrays - # can easily cause a stack overflow. - root = self - while parent.__class__ == TVar and root is not parent: - _, parent = root, root.parent = parent, parent.parent - return root.parent - - def unify(self, other): - if other is self: - return - x = other.find() - y = self.find() - if x is y: - return - if y.__class__ == TVar: - if x.__class__ == TVar: - if x.rank < y.rank: - x, y = y, x - y.parent = x - if x.rank == y.rank: - x.rank += 1 - else: - y.parent = x - else: - y.unify(x) - - def fold(self, accum, fn): - if self.parent is self: - return fn(accum, self) - else: - return self.find().fold(accum, fn) - - def __repr__(self): - if getattr(builtins, "__in_sphinx__", False): - return str(self) - if self.parent is self: - return "" % id(self) - else: - return repr(self.find()) - - # __eq__ and __hash__ are not overridden and default to - # comparison by identity. Use .find() explicitly before - # any lookups or comparisons. - -class TMono(Type): - """ - A monomorphic type, possibly parametric. - - :class:`TMono` is supposed to be subclassed by builtin types, - unlike all other :class:`Type` descendants. Similarly, - instances of :class:`TMono` should never be allocated directly, - as that will break the type-sniffing code in :mod:`builtins`. - """ - - attributes = OrderedDict() - - def __init__(self, name, params={}): - assert isinstance(params, (dict, OrderedDict)) - self.name, self.params = name, OrderedDict(sorted(params.items())) - - def find(self): - return self - - def unify(self, other): - if other is self: - return - if isinstance(other, TMono) and self.name == other.name: - assert self.params.keys() == other.params.keys() - for param in self.params: - self.params[param].unify(other.params[param]) - elif isinstance(other, TVar): - other.unify(self) - else: - raise UnificationError(self, other) - - def fold(self, accum, fn): - for param in self.params: - accum = self.params[param].fold(accum, fn) - return fn(accum, self) - - def __repr__(self): - if getattr(builtins, "__in_sphinx__", False): - return str(self) - return "artiq.compiler.types.TMono(%s, %s)" % (repr(self.name), repr(self.params)) - - def __getitem__(self, param): - return self.params[param] - - def __eq__(self, other): - return isinstance(other, TMono) and \ - self.name == other.name and \ - _map_find(self.params) == _map_find(other.params) - - def __ne__(self, other): - return not (self == other) - - def __hash__(self): - return hash((self.name, _freeze(self.params))) - -class TTuple(Type): - """ - A tuple type. - - :ivar elts: (list of :class:`Type`) elements - """ - - attributes = OrderedDict() - - def __init__(self, elts=[]): - self.elts = elts - - def find(self): - return self - - def unify(self, other): - if other is self: - return - if isinstance(other, TTuple) and len(self.elts) == len(other.elts): - for selfelt, otherelt in zip(self.elts, other.elts): - selfelt.unify(otherelt) - elif isinstance(other, TVar): - other.unify(self) - else: - raise UnificationError(self, other) - - def fold(self, accum, fn): - for elt in self.elts: - accum = elt.fold(accum, fn) - return fn(accum, self) - - def __repr__(self): - if getattr(builtins, "__in_sphinx__", False): - return str(self) - return "artiq.compiler.types.TTuple(%s)" % repr(self.elts) - - def __eq__(self, other): - return isinstance(other, TTuple) and \ - _map_find(self.elts) == _map_find(other.elts) - - def __ne__(self, other): - return not (self == other) - - def __hash__(self): - return hash(tuple(self.elts)) - -class _TPointer(TMono): - def __init__(self, elt=None): - if elt is None: - elt = TMono("int", {"width": 8}) # i8* - super().__init__("pointer", params={"elt": elt}) - -class TFunction(Type): - """ - A function type. - - :ivar args: (:class:`collections.OrderedDict` of string to :class:`Type`) - mandatory arguments - :ivar optargs: (:class:`collections.OrderedDict` of string to :class:`Type`) - optional arguments - :ivar ret: (:class:`Type`) - return type - :ivar delay: (:class:`Type`) - RTIO delay - """ - - attributes = OrderedDict([ - ('__closure__', _TPointer()), - ('__code__', _TPointer()), - ]) - - def __init__(self, args, optargs, ret): - assert isinstance(args, OrderedDict) - assert isinstance(optargs, OrderedDict) - assert isinstance(ret, Type) - self.args, self.optargs, self.ret = args, optargs, ret - self.delay = TVar() - - def arity(self): - return len(self.args) + len(self.optargs) - - def arg_names(self): - return list(self.args.keys()) + list(self.optargs.keys()) - - def find(self): - return self - - def unify(self, other): - if other is self: - return - if isinstance(other, TFunction) and \ - self.args.keys() == other.args.keys() and \ - self.optargs.keys() == other.optargs.keys(): - for selfarg, otherarg in zip(list(self.args.values()) + list(self.optargs.values()), - list(other.args.values()) + list(other.optargs.values())): - selfarg.unify(otherarg) - self.ret.unify(other.ret) - self.delay.unify(other.delay) - elif isinstance(other, TVar): - other.unify(self) - else: - raise UnificationError(self, other) - - def fold(self, accum, fn): - for arg in self.args: - accum = self.args[arg].fold(accum, fn) - for optarg in self.optargs: - accum = self.optargs[optarg].fold(accum, fn) - accum = self.ret.fold(accum, fn) - return fn(accum, self) - - def __repr__(self): - if getattr(builtins, "__in_sphinx__", False): - return str(self) - return "artiq.compiler.types.TFunction({}, {}, {})".format( - repr(self.args), repr(self.optargs), repr(self.ret)) - - def __eq__(self, other): - return isinstance(other, TFunction) and \ - _map_find(self.args) == _map_find(other.args) and \ - _map_find(self.optargs) == _map_find(other.optargs) - - def __ne__(self, other): - return not (self == other) - - def __hash__(self): - return hash((_freeze(self.args), _freeze(self.optargs), self.ret)) - -class TExternalFunction(TFunction): - """ - A type of an externally-provided function. - - This can be any function following the C ABI, such as provided by the - C/Rust runtime, or a compiler backend intrinsic. The mangled name to link - against is encoded as part of the type. - - :ivar name: (str) external symbol name. - This will be the symbol linked against (following any extra C name - mangling rules). - :ivar flags: (set of str) function flags. - Flag ``nounwind`` means the function never raises an exception. - Flag ``nowrite`` means the function never accesses any memory - that the ARTIQ Python code can observe. - :ivar broadcast_across_arrays: (bool) - If True, the function is transparently applied element-wise when called - with TArray arguments. - """ - - attributes = OrderedDict() - - def __init__(self, args, ret, name, flags=set(), broadcast_across_arrays=False): - assert isinstance(flags, set) - for flag in flags: - assert flag in {'nounwind', 'nowrite'} - super().__init__(args, OrderedDict(), ret) - self.name = name - self.delay = TFixedDelay(iodelay.Const(0)) - self.flags = flags - self.broadcast_across_arrays = broadcast_across_arrays - - def unify(self, other): - if other is self: - return - if isinstance(other, TExternalFunction) and \ - self.name == other.name: - super().unify(other) - elif isinstance(other, TVar): - other.unify(self) - else: - raise UnificationError(self, other) - -class TRPC(Type): - """ - A type of a remote call. - - :ivar ret: (:class:`Type`) - return type - :ivar service: (int) RPC service number - :ivar is_async: (bool) whether the RPC blocks until return - """ - - attributes = OrderedDict() - - def __init__(self, ret, service, is_async=False): - assert isinstance(ret, Type) - self.ret, self.service, self.is_async = ret, service, is_async - - def find(self): - return self - - def unify(self, other): - if other is self: - return - if isinstance(other, TRPC) and \ - self.service == other.service and \ - self.is_async == other.is_async: - self.ret.unify(other.ret) - elif isinstance(other, TVar): - other.unify(self) - else: - raise UnificationError(self, other) - - def fold(self, accum, fn): - accum = self.ret.fold(accum, fn) - return fn(accum, self) - - def __repr__(self): - if getattr(builtins, "__in_sphinx__", False): - return str(self) - return "artiq.compiler.types.TRPC({})".format(repr(self.ret)) - - def __eq__(self, other): - return isinstance(other, TRPC) and \ - self.service == other.service and \ - self.is_async == other.is_async - - def __ne__(self, other): - return not (self == other) - - def __hash__(self): - return hash(self.service) - -class TBuiltin(Type): - """ - An instance of builtin type. Every instance of a builtin - type is treated specially according to its name. - """ - - def __init__(self, name): - assert isinstance(name, str) - self.name = name - self.attributes = OrderedDict() - - def find(self): - return self - - def unify(self, other): - if other is self: - return - if self != other: - raise UnificationError(self, other) - - def fold(self, accum, fn): - return fn(accum, self) - - def __repr__(self): - if getattr(builtins, "__in_sphinx__", False): - return str(self) - return "artiq.compiler.types.{}({})".format(type(self).__name__, repr(self.name)) - - def __eq__(self, other): - return isinstance(other, TBuiltin) and \ - self.name == other.name - - def __ne__(self, other): - return not (self == other) - - def __hash__(self): - return hash(self.name) - -class TBuiltinFunction(TBuiltin): - """ - A type of a builtin function. - - Builtin functions are treated specially throughout all stages of the - compilation process according to their name (e.g. calls may not actually - lower to a function call). See :class:`TExternalFunction` for externally - defined functions that are otherwise regular. - """ - -class TConstructor(TBuiltin): - """ - A type of a constructor of a class, e.g. ``list``. - Note that this is not the same as the type of an instance of - the class, which is ``TMono("list", ...)`` (or a descendant). - - :ivar instance: (:class:`Type`) - the type of the instance created by this constructor - """ - - def __init__(self, instance): - assert isinstance(instance, TMono) - super().__init__(instance.name) - self.instance = instance - -class TExceptionConstructor(TConstructor): - """ - A type of a constructor of an exception, e.g. ``Exception``. - Note that this is not the same as the type of an instance of - the class, which is ``TMono("Exception", ...)``. - """ - -class TInstance(TMono): - """ - A type of an instance of a user-defined class. - - :ivar constructor: (:class:`TConstructor`) - the type of the constructor with which this instance - was created - """ - - def __init__(self, name, attributes): - assert isinstance(attributes, OrderedDict) - super().__init__(name) - self.attributes = attributes - self.constant_attributes = set() - - def __repr__(self): - if getattr(builtins, "__in_sphinx__", False): - return str(self) - return "artiq.compiler.types.TInstance({}, {})".format( - repr(self.name), repr(self.attributes)) - -class TModule(TMono): - """ - A type of a module. - """ - - def __init__(self, name, attributes): - assert isinstance(attributes, OrderedDict) - super().__init__(name) - self.attributes = attributes - self.constant_attributes = set() - - def __repr__(self): - if getattr(builtins, "__in_sphinx__", False): - return str(self) - return "artiq.compiler.types.TModule({}, {})".format( - repr(self.name), repr(self.attributes)) - -class TMethod(TMono): - """ - A type of a method. - """ - - def __init__(self, self_type, function_type): - super().__init__("method", {"self": self_type, "fn": function_type}) - self.attributes = OrderedDict([ - ("__func__", function_type), - ("__self__", self_type), - ]) - -class TValue(Type): - """ - A type-level value (such as the integer denoting width of - a generic integer type. - """ - - def __init__(self, value): - self.value = value - - def find(self): - return self - - def unify(self, other): - if other is self: - return - if isinstance(other, TVar): - other.unify(self) - elif self != other: - raise UnificationError(self, other) - - def fold(self, accum, fn): - return fn(accum, self) - - def __repr__(self): - if getattr(builtins, "__in_sphinx__", False): - return str(self) - return "artiq.compiler.types.TValue(%s)" % repr(self.value) - - def __eq__(self, other): - return isinstance(other, TValue) and \ - self.value == other.value - - def __ne__(self, other): - return not (self == other) - - def __hash__(self): - return hash(self.value) - -class TDelay(Type): - """ - The type-level representation of IO delay. - """ - - def __init__(self, duration, cause): - # Avoid pulling in too many dependencies with `artiq.language`. - from pythonparser import diagnostic - assert duration is None or isinstance(duration, iodelay.Expr) - assert cause is None or isinstance(cause, diagnostic.Diagnostic) - assert (not (duration and cause)) and (duration or cause) - self.duration, self.cause = duration, cause - - def is_fixed(self): - return self.duration is not None - - def is_indeterminate(self): - return self.cause is not None - - def find(self): - return self - - def unify(self, other): - other = other.find() - - if isinstance(other, TVar): - other.unify(self) - elif self.is_fixed() and other.is_fixed() and \ - self.duration.fold() == other.duration.fold(): - pass - elif self is not other: - raise UnificationError(self, other) - - def fold(self, accum, fn): - # delay types do not participate in folding - pass - - def __eq__(self, other): - return isinstance(other, TDelay) and \ - (self.duration == other.duration and \ - self.cause == other.cause) - - def __ne__(self, other): - return not (self == other) - - def __repr__(self): - if getattr(builtins, "__in_sphinx__", False): - return str(self) - if self.duration is None: - return "<{}.TIndeterminateDelay>".format(__name__) - elif self.cause is None: - return "{}.TFixedDelay({})".format(__name__, self.duration) - else: - assert False - -def TIndeterminateDelay(cause): - return TDelay(None, cause) - -def TFixedDelay(duration): - return TDelay(duration, None) - - -def is_var(typ): - return isinstance(typ.find(), TVar) - -def is_mono(typ, name=None, **params): - typ = typ.find() - - if not isinstance(typ, TMono): - return False - - if name is not None and typ.name != name: - return False - - for param in params: - if param not in typ.params: - return False - if typ.params[param].find() != params[param].find(): - return False - return True - -def is_polymorphic(typ): - return typ.fold(False, lambda accum, typ: accum or is_var(typ)) - -def is_tuple(typ, elts=None): - typ = typ.find() - if elts: - return isinstance(typ, TTuple) and \ - elts == typ.elts - else: - return isinstance(typ, TTuple) - -def _is_pointer(typ): - return isinstance(typ.find(), _TPointer) - -def is_function(typ): - return isinstance(typ.find(), TFunction) - -def is_rpc(typ): - return isinstance(typ.find(), TRPC) - -def is_external_function(typ, name=None): - typ = typ.find() - if name is None: - return isinstance(typ, TExternalFunction) - else: - return isinstance(typ, TExternalFunction) and \ - typ.name == name - -def is_builtin(typ, name=None): - typ = typ.find() - if name is None: - return isinstance(typ, TBuiltin) - else: - return isinstance(typ, TBuiltin) and \ - typ.name == name - -def is_builtin_function(typ, name=None): - typ = typ.find() - if name is None: - return isinstance(typ, TBuiltinFunction) - else: - return isinstance(typ, TBuiltinFunction) and \ - typ.name == name - -def is_broadcast_across_arrays(typ): - # For now, broadcasting is only exposed to predefined external functions, and - # statically selected. Might be extended to user-defined functions if the design - # pans out. - typ = typ.find() - if not isinstance(typ, TExternalFunction): - return False - return typ.broadcast_across_arrays - -def is_constructor(typ, name=None): - typ = typ.find() - if name is not None: - return isinstance(typ, TConstructor) and \ - typ.name == name - else: - return isinstance(typ, TConstructor) - -def is_exn_constructor(typ, name=None): - typ = typ.find() - if name is not None: - return isinstance(typ, TExceptionConstructor) and \ - typ.name == name - else: - return isinstance(typ, TExceptionConstructor) - -def is_instance(typ, name=None): - typ = typ.find() - if name is not None: - return isinstance(typ, TInstance) and \ - typ.name == name - else: - return isinstance(typ, TInstance) - -def is_module(typ, name=None): - typ = typ.find() - if name is not None: - return isinstance(typ, TModule) and \ - typ.name == name - else: - return isinstance(typ, TModule) - -def is_method(typ): - return isinstance(typ.find(), TMethod) - -def get_method_self(typ): - if is_method(typ): - return typ.find().params["self"].find() - -def get_method_function(typ): - if is_method(typ): - return typ.find().params["fn"].find() - -def is_value(typ): - return isinstance(typ.find(), TValue) - -def get_value(typ): - typ = typ.find() - if isinstance(typ, TVar): - return None - elif isinstance(typ, TValue): - return typ.value - else: - assert False - -def is_delay(typ): - return isinstance(typ.find(), TDelay) - -def is_fixed_delay(typ): - return is_delay(typ) and typ.find().is_fixed() - -def is_indeterminate_delay(typ): - return is_delay(typ) and typ.find().is_indeterminate() - - -class TypePrinter(object): - """ - A class that prints types using Python-like syntax and gives - type variables sequential alphabetic names. - """ - - custom_printers = {} - - def __init__(self): - self.gen = genalnum() - self.map = {} - self.recurse_guard = set() - - def name(self, typ, depth=0, max_depth=1): - typ = typ.find() - if isinstance(typ, TVar): - if typ not in self.map: - self.map[typ] = "'%s" % next(self.gen) - return self.map[typ] - elif isinstance(typ, TInstance): - if typ in self.recurse_guard or depth >= max_depth: - return "".format(typ.name) - elif len(typ.attributes) > 0: - self.recurse_guard.add(typ) - attrs = ",\n\t\t".join(["{}: {}".format(attr, self.name(typ.attributes[attr], - depth + 1)) - for attr in typ.attributes]) - return "".format(typ.name, attrs) - else: - self.recurse_guard.add(typ) - return "".format(typ.name) - elif isinstance(typ, TMono): - if typ.name in self.custom_printers: - return self.custom_printers[typ.name](typ, self, depth + 1, max_depth) - elif typ.params == {}: - return typ.name - else: - return "%s(%s)" % (typ.name, ", ".join( - ["%s=%s" % (k, self.name(typ.params[k], depth + 1)) for k in typ.params])) - elif isinstance(typ, _TPointer): - return "{}*".format(self.name(typ["elt"], depth + 1)) - elif isinstance(typ, TTuple): - if len(typ.elts) == 1: - return "(%s,)" % self.name(typ.elts[0], depth + 1) - else: - return "(%s)" % ", ".join([self.name(typ, depth + 1) for typ in typ.elts]) - elif isinstance(typ, (TFunction, TExternalFunction)): - args = [] - args += [ "%s:%s" % (arg, self.name(typ.args[arg], depth + 1)) - for arg in typ.args] - args += ["?%s:%s" % (arg, self.name(typ.optargs[arg], depth + 1)) - for arg in typ.optargs] - signature = "(%s)->%s" % (", ".join(args), self.name(typ.ret, depth + 1)) - - delay = typ.delay.find() - if isinstance(delay, TVar): - signature += " delay({})".format(self.name(delay, depth + 1)) - elif not (delay.is_fixed() and iodelay.is_zero(delay.duration)): - signature += " " + self.name(delay, depth + 1) - - if isinstance(typ, TExternalFunction): - return "[ffi {}]{}".format(repr(typ.name), signature) - elif isinstance(typ, TFunction): - return signature - elif isinstance(typ, TRPC): - return "[rpc{} #{}](...)->{}".format(typ.service, - " async" if typ.is_async else "", - self.name(typ.ret, depth + 1)) - elif isinstance(typ, TBuiltinFunction): - return "".format(typ.name) - elif isinstance(typ, (TConstructor, TExceptionConstructor)): - if typ in self.recurse_guard or depth >= max_depth: - return "".format(typ.name) - elif len(typ.attributes) > 0: - self.recurse_guard.add(typ) - attrs = ", ".join(["{}: {}".format(attr, self.name(typ.attributes[attr], - depth + 1)) - for attr in typ.attributes]) - return "".format(typ.name, attrs) - else: - self.recurse_guard.add(typ) - return "".format(typ.name) - elif isinstance(typ, TBuiltin): - return "".format(typ.name) - elif isinstance(typ, TValue): - return repr(typ.value) - elif isinstance(typ, TDelay): - if typ.is_fixed(): - return "delay({} mu)".format(typ.duration) - elif typ.is_indeterminate(): - return "delay(?)" - else: - assert False - else: - assert False diff --git a/artiq/compiler/validators/__init__.py b/artiq/compiler/validators/__init__.py deleted file mode 100644 index ccbaa8827..000000000 --- a/artiq/compiler/validators/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .monomorphism import MonomorphismValidator -from .escape import EscapeValidator -from .local_access import LocalAccessValidator -from .constness import ConstnessValidator diff --git a/artiq/compiler/validators/constness.py b/artiq/compiler/validators/constness.py deleted file mode 100644 index fb1123c49..000000000 --- a/artiq/compiler/validators/constness.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -:class:`ConstnessValidator` checks that no attribute marked -as constant is ever set. -""" - -from pythonparser import algorithm, diagnostic -from .. import types, builtins - -class ConstnessValidator(algorithm.Visitor): - def __init__(self, engine): - self.engine = engine - self.in_assign = False - - def visit_Assign(self, node): - self.visit(node.value) - self.in_assign = True - self.visit(node.targets) - self.in_assign = False - - def visit_AugAssign(self, node): - self.visit(node.value) - self.in_assign = True - self.visit(node.target) - self.in_assign = False - - def visit_SubscriptT(self, node): - old_in_assign, self.in_assign = self.in_assign, False - self.visit(node.value) - self.visit(node.slice) - self.in_assign = old_in_assign - - if self.in_assign and builtins.is_bytes(node.value.type): - diag = diagnostic.Diagnostic("error", - "type {typ} is not mutable", - {"typ": "bytes"}, - node.loc) - self.engine.process(diag) - - def visit_AttributeT(self, node): - old_in_assign, self.in_assign = self.in_assign, False - self.visit(node.value) - self.in_assign = old_in_assign - - if self.in_assign: - typ = node.value.type.find() - if types.is_instance(typ) and node.attr in typ.constant_attributes: - diag = diagnostic.Diagnostic("error", - "cannot assign to constant attribute '{attr}' of class '{class}'", - {"attr": node.attr, "class": typ.name}, - node.loc) - self.engine.process(diag) - return - if builtins.is_array(typ): - diag = diagnostic.Diagnostic("error", - "array attributes cannot be assigned to", - {}, node.loc) - self.engine.process(diag) - return diff --git a/artiq/compiler/validators/escape.py b/artiq/compiler/validators/escape.py deleted file mode 100644 index c6ae59704..000000000 --- a/artiq/compiler/validators/escape.py +++ /dev/null @@ -1,360 +0,0 @@ -""" -:class:`EscapeValidator` verifies that no mutable data escapes -the region of its allocation. -""" - -import functools -from pythonparser import algorithm, diagnostic -from .. import asttyped, types, builtins - -def has_region(typ): - return typ.fold(False, lambda accum, typ: accum or builtins.is_allocated(typ)) - -class Global: - def __repr__(self): - return "Global()" - -class Argument: - def __init__(self, loc): - self.loc = loc - - def __repr__(self): - return "Argument()" - -class Region: - """ - A last-in-first-out allocation region. Tied to lexical scoping - and is internally represented simply by a source range. - - :ivar range: (:class:`pythonparser.source.Range` or None) - """ - - def __init__(self, source_range=None): - self.range = source_range - - def present(self): - return bool(self.range) - - def includes(self, other): - assert self.range - assert self.range.source_buffer == other.range.source_buffer - - return self.range.begin_pos <= other.range.begin_pos and \ - self.range.end_pos >= other.range.end_pos - - def intersects(self, other): - assert self.range - assert self.range.source_buffer == other.range.source_buffer - - return (self.range.begin_pos <= other.range.begin_pos <= self.range.end_pos and \ - other.range.end_pos > self.range.end_pos) or \ - (other.range.begin_pos <= self.range.begin_pos <= other.range.end_pos and \ - self.range.end_pos > other.range.end_pos) - - def outlives(lhs, rhs): - if not isinstance(lhs, Region): # lhs lives nonlexically - return True - elif not isinstance(rhs, Region): # rhs lives nonlexically, lhs does not - return False - else: - assert not lhs.intersects(rhs) - return lhs.includes(rhs) - - def __repr__(self): - return "Region({})".format(repr(self.range)) - -class RegionOf(algorithm.Visitor): - """ - Visit an expression and return the region that must be alive for the - expression to execute. - - For expressions involving multiple regions, the shortest-lived one is - returned. - """ - - def __init__(self, env_stack, youngest_region): - self.env_stack, self.youngest_region = env_stack, youngest_region - - # Liveness determined by assignments - def visit_NameT(self, node): - # First, look at stack regions - for region in reversed(self.env_stack[1:]): - if node.id in region: - return region[node.id] - - # Then, look at the global region of this module - if node.id in self.env_stack[0]: - return Global() - - assert False - - # Value lives as long as the current scope, if it's mutable, - # or else forever - def visit_sometimes_allocating(self, node): - if has_region(node.type): - return self.youngest_region - else: - return Global() - - visit_BinOpT = visit_sometimes_allocating - - def visit_CallT(self, node): - if types.is_external_function(node.func.type, "cache_get"): - # The cache is borrow checked dynamically - return Global() - else: - self.visit_sometimes_allocating(node) - - # Value lives as long as the object/container, if it's mutable, - # or else forever - def visit_accessor(self, node): - if has_region(node.type): - return self.visit(node.value) - else: - return Global() - - visit_AttributeT = visit_accessor - visit_SubscriptT = visit_accessor - - # Value lives as long as the shortest living operand - def visit_selecting(self, nodes): - regions = [self.visit(node) for node in nodes] - regions = list(filter(lambda x: x, regions)) - if any(regions): - regions.sort(key=functools.cmp_to_key(Region.outlives), reverse=True) - return regions[0] - else: - return Global() - - def visit_BoolOpT(self, node): - return self.visit_selecting(node.values) - - def visit_IfExpT(self, node): - return self.visit_selecting([node.body, node.orelse]) - - def visit_TupleT(self, node): - return self.visit_selecting(node.elts) - - # Value lives as long as the current scope - def visit_allocating(self, node): - return self.youngest_region - - visit_DictT = visit_allocating - visit_DictCompT = visit_allocating - visit_GeneratorExpT = visit_allocating - visit_LambdaT = visit_allocating - visit_ListT = visit_allocating - visit_ListCompT = visit_allocating - visit_SetT = visit_allocating - visit_SetCompT = visit_allocating - - # Value lives forever - def visit_immutable(self, node): - assert not has_region(node.type) - return Global() - - visit_NameConstantT = visit_immutable - visit_NumT = visit_immutable - visit_EllipsisT = visit_immutable - visit_UnaryOpT = visit_sometimes_allocating # possibly array op - visit_CompareT = visit_immutable - - # Value lives forever - def visit_global(self, node): - return Global() - - visit_StrT = visit_global - visit_QuoteT = visit_global - - # Not implemented - def visit_unimplemented(self, node): - assert False - - visit_StarredT = visit_unimplemented - visit_YieldT = visit_unimplemented - visit_YieldFromT = visit_unimplemented - - -class AssignedNamesOf(algorithm.Visitor): - """ - Visit an expression and return the list of names that appear - on the lhs of assignment, directly or through an accessor. - """ - - def visit_name(self, node): - return [node] - - visit_NameT = visit_name - visit_QuoteT = visit_name - - def visit_accessor(self, node): - return self.visit(node.value) - - visit_AttributeT = visit_accessor - visit_SubscriptT = visit_accessor - - def visit_sequence(self, node): - return functools.reduce(list.__add__, map(self.visit, node.elts)) - - visit_TupleT = visit_sequence - visit_ListT = visit_sequence - - def visit_StarredT(self, node): - assert False - - -class EscapeValidator(algorithm.Visitor): - def __init__(self, engine): - self.engine = engine - self.youngest_region = Global() - self.env_stack = [] - self.youngest_env = None - - def _region_of(self, expr): - return RegionOf(self.env_stack, self.youngest_region).visit(expr) - - def _names_of(self, expr): - return AssignedNamesOf().visit(expr) - - def _diagnostics_for(self, region, loc, descr="the value of the expression"): - if isinstance(region, Region): - return [ - diagnostic.Diagnostic("note", - "{descr} is alive from this point...", {"descr": descr}, - region.range.begin()), - diagnostic.Diagnostic("note", - "... to this point", {}, - region.range.end()) - ] - elif isinstance(region, Global): - return [ - diagnostic.Diagnostic("note", - "{descr} is alive forever", {"descr": descr}, - loc) - ] - elif isinstance(region, Argument): - return [ - diagnostic.Diagnostic("note", - "{descr} is still alive after this function returns", {"descr": descr}, - loc), - diagnostic.Diagnostic("note", - "{descr} is introduced here as a formal argument", {"descr": descr}, - region.loc) - ] - else: - assert False - - def visit_in_region(self, node, region, typing_env, args=[]): - try: - old_youngest_region = self.youngest_region - self.youngest_region = region - - old_youngest_env = self.youngest_env - self.youngest_env = {} - - for name in typing_env: - if has_region(typing_env[name]): - if name in args: - self.youngest_env[name] = args[name] - else: - self.youngest_env[name] = Region(None) # not yet known - else: - self.youngest_env[name] = Global() - self.env_stack.append(self.youngest_env) - - self.generic_visit(node) - finally: - self.env_stack.pop() - self.youngest_env = old_youngest_env - self.youngest_region = old_youngest_region - - def visit_ModuleT(self, node): - self.visit_in_region(node, None, node.typing_env) - - def visit_FunctionDefT(self, node): - self.youngest_env[node.name] = self.youngest_region - self.visit_in_region(node, Region(node.loc), node.typing_env, - args={ arg.arg: Argument(arg.loc) for arg in node.args.args }) - - visit_QuotedFunctionDefT = visit_FunctionDefT - - def visit_ClassDefT(self, node): - self.youngest_env[node.name] = self.youngest_region - self.visit_in_region(node, Region(node.loc), node.constructor_type.attributes) - - # Only three ways for a pointer to escape: - # * Assigning or op-assigning it (we ensure an outlives relationship) - # * Returning it (we only allow returning values that live forever) - # * Raising it (we forbid allocating exceptions that refer to mutable data)¹ - # - # Literals doesn't count: a constructed object is always - # outlived by all its constituents. - # Closures don't count: see above. - # Calling functions doesn't count: arguments never outlive - # the function body. - # - # ¹Strings are currently never allocated with a limited lifetime, - # and exceptions can only refer to strings, so we don't actually check - # this property. But we will need to, if string operations are ever added. - - def visit_assignment(self, target, value): - value_region = self._region_of(value) - - # If we assign to an attribute of a quoted value, there will be no names - # in the assignment lhs. - target_names = self._names_of(target) or [] - - # Adopt the value region for any variables declared on the lhs. - for name in target_names: - region = self._region_of(name) - if isinstance(region, Region) and not region.present(): - # Find the name's environment to overwrite the region. - for env in self.env_stack[::-1]: - if name.id in env: - env[name.id] = value_region - break - - # The assigned value should outlive the assignee - target_regions = [self._region_of(name) for name in target_names] - for target_region in target_regions: - if not Region.outlives(value_region, target_region): - diag = diagnostic.Diagnostic("error", - "the assigned value does not outlive the assignment target", {}, - value.loc, [target.loc], - notes=self._diagnostics_for(target_region, target.loc, - "the assignment target") + - self._diagnostics_for(value_region, value.loc, - "the assigned value")) - self.engine.process(diag) - - def visit_Assign(self, node): - for target in node.targets: - self.visit_assignment(target, node.value) - - def visit_AugAssign(self, node): - if builtins.is_list(node.target.type): - note = diagnostic.Diagnostic("note", - "try using `{lhs} = {lhs} {op} {rhs}` instead", - {"lhs": node.target.loc.source(), - "rhs": node.value.loc.source(), - "op": node.op.loc.source()[:-1]}, - node.loc) - diag = diagnostic.Diagnostic("error", - "lists cannot be mutated in-place", {}, - node.op.loc, [node.target.loc], - notes=[note]) - self.engine.process(diag) - - self.visit_assignment(node.target, node.value) - - def visit_Return(self, node): - region = self._region_of(node.value) - if isinstance(region, Region): - note = diagnostic.Diagnostic("note", - "this expression has type {type}", - {"type": types.TypePrinter().name(node.value.type)}, - node.value.loc) - diag = diagnostic.Diagnostic("error", - "cannot return an allocated value that does not live forever", {}, - node.value.loc, notes=self._diagnostics_for(region, node.value.loc) + [note]) - self.engine.process(diag) diff --git a/artiq/compiler/validators/local_access.py b/artiq/compiler/validators/local_access.py deleted file mode 100644 index 55ed7bd0d..000000000 --- a/artiq/compiler/validators/local_access.py +++ /dev/null @@ -1,187 +0,0 @@ -""" -:class:`LocalAccessValidator` verifies that local variables -are not accessed before being used. -""" - -from functools import reduce -from pythonparser import diagnostic -from .. import ir, analyses - -def is_special_variable(name): - return "$" in name - -class LocalAccessValidator: - def __init__(self, engine): - self.engine = engine - - def process(self, functions): - for func in functions: - self.process_function(func) - - def process_function(self, func): - # Find all environments and closures allocated in this func. - environments, closures = [], [] - for insn in func.instructions(): - if isinstance(insn, ir.Alloc) and ir.is_environment(insn.type): - environments.append(insn) - elif isinstance(insn, ir.Closure): - closures.append(insn) - - # Compute initial state of interesting environments. - # Environments consisting only of internal variables (containing a ".") - # are ignored. - initial_state = {} - for env in environments: - env_state = {var: False for var in env.type.params if "." not in var} - if any(env_state): - initial_state[env] = env_state - - # Traverse the acyclic graph made of basic blocks and forward edges only, - # while updating the environment state. - domtree = analyses.DominatorTree(func) - state = {} - def traverse(block): - # Have we computed the state of this block already? - if block in state: - return state[block] - - # No! Which forward edges lead to this block? - # If we dominate a predecessor, it's a back edge instead. - forward_edge_preds = [pred for pred in block.predecessors() - if block not in domtree.dominators(pred)] - - # Figure out what the state is before the leader - # instruction of this block. - pred_states = [traverse(pred) for pred in forward_edge_preds] - block_state = {} - if len(pred_states) > 1: - for env in initial_state: - # The variable has to be initialized in all predecessors - # in order to be initialized in this block. - def merge_state(a, b): - return {var: a[var] and b[var] for var in a} - block_state[env] = reduce(merge_state, - [state[env] for state in pred_states]) - elif len(pred_states) == 1: - # The state is the same as at the terminator of predecessor. - # We'll mutate it, so copy. - pred_state = pred_states[0] - for env in initial_state: - env_state = pred_state[env] - block_state[env] = {var: env_state[var] for var in env_state} - else: - # This is the entry block. - for env in initial_state: - env_state = initial_state[env] - block_state[env] = {var: env_state[var] for var in env_state} - - # Update the state based on block contents, while validating - # that no access to uninitialized variables will be done. - for insn in block.instructions: - def pred_at_fault(env, var_name): - # Find out where the uninitialized state comes from. - for pred, pred_state in zip(forward_edge_preds, pred_states): - if not pred_state[env][var_name]: - return pred - - # It's the entry block and it was never initialized. - return None - - set_local_in_this_frame = False - if (isinstance(insn, (ir.SetLocal, ir.GetLocal)) and - not is_special_variable(insn.var_name)): - env, var_name = insn.environment(), insn.var_name - - # Make sure that the variable is defined in the scope of this function. - if env in block_state and var_name in block_state[env]: - if isinstance(insn, ir.SetLocal): - # We've just initialized it. - block_state[env][var_name] = True - set_local_in_this_frame = True - else: # isinstance(insn, ir.GetLocal) - if not block_state[env][var_name]: - # Oops, accessing it uninitialized. - self._uninitialized_access(insn, var_name, - pred_at_fault(env, var_name)) - - closures_to_check = [] - - if (isinstance(insn, (ir.SetLocal, ir.SetAttr, ir.SetElem)) and - not set_local_in_this_frame): - # Closures may escape via these mechanisms and be invoked elsewhere. - if isinstance(insn.value(), ir.Closure): - closures_to_check.append(insn.value()) - - if isinstance(insn, (ir.Call, ir.Invoke)): - # We can't always trace the flow of closures from point of - # definition to point of call; however, we know that, by transitiveness - # of this analysis, only closures defined in this function can contain - # uninitialized variables. - # - # Thus, enumerate the closures, and check all of them during any operation - # that may eventually result in the closure being called. - closures_to_check = closures - - for closure in closures_to_check: - env = closure.environment() - # Make sure this environment has any interesting variables. - if env in block_state: - for var_name in block_state[env]: - if not block_state[env][var_name] and not is_special_variable(var_name): - # A closure would capture this variable while it is not always - # initialized. Note that this check is transitive. - self._uninitialized_access(closure, var_name, - pred_at_fault(env, var_name)) - - # Save the state. - state[block] = block_state - - return block_state - - for block in func.basic_blocks: - traverse(block) - - def _uninitialized_access(self, insn, var_name, pred_at_fault): - if pred_at_fault is not None: - visited = set() - possible_preds = [pred_at_fault] - - uninitialized_loc = None - while uninitialized_loc is None: - possible_pred = possible_preds.pop(0) - visited.add(possible_pred) - - for pred_insn in reversed(possible_pred.instructions): - if pred_insn.loc is not None: - uninitialized_loc = pred_insn.loc.begin() - break - - for block in possible_pred.predecessors(): - if block not in visited: - possible_preds.append(block) - - assert uninitialized_loc is not None - - note = diagnostic.Diagnostic("note", - "variable is not initialized when control flows from this point", {}, - uninitialized_loc) - else: - note = None - - if note is not None: - notes = [note] - else: - notes = [] - - if isinstance(insn, ir.Closure): - diag = diagnostic.Diagnostic("error", - "variable '{name}' can be captured in a closure uninitialized here", - {"name": var_name}, - insn.loc, notes=notes) - else: - diag = diagnostic.Diagnostic("error", - "variable '{name}' is not always initialized here", - {"name": var_name}, - insn.loc, notes=notes) - - self.engine.process(diag) diff --git a/artiq/compiler/validators/monomorphism.py b/artiq/compiler/validators/monomorphism.py deleted file mode 100644 index 0911deb40..000000000 --- a/artiq/compiler/validators/monomorphism.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -:class:`MonomorphismValidator` verifies that all type variables have been -elided, which is necessary for code generation. -""" - -from pythonparser import algorithm, diagnostic -from .. import asttyped, types, builtins - -class MonomorphismValidator(algorithm.Visitor): - def __init__(self, engine): - self.engine = engine - - def visit_FunctionDefT(self, node): - super().generic_visit(node) - - return_type = node.signature_type.find().ret - if types.is_polymorphic(return_type): - note = diagnostic.Diagnostic("note", - "the function has return type {type}", - {"type": types.TypePrinter().name(return_type)}, - node.name_loc) - diag = diagnostic.Diagnostic("error", - "the return type of this function cannot be fully inferred", {}, - node.name_loc, notes=[note]) - self.engine.process(diag) - - visit_QuotedFunctionDefT = visit_FunctionDefT - - def generic_visit(self, node): - super().generic_visit(node) - - if isinstance(node, asttyped.commontyped): - if types.is_polymorphic(node.type): - note = diagnostic.Diagnostic("note", - "the expression has type {type}", - {"type": types.TypePrinter().name(node.type)}, - node.loc) - diag = diagnostic.Diagnostic("error", - "the type of this expression cannot be fully inferred", {}, - node.loc, notes=[note]) - self.engine.process(diag) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index dc8207266..191a90de7 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -1,8 +1,6 @@ import os, sys import numpy -from pythonparser import diagnostic - from artiq import __artiq_dir__ as artiq_dir from artiq.language.core import * diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index 21baf3f05..e29eef8d1 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -10,8 +10,6 @@ from collections import defaultdict import h5py -from llvmlite import binding as llvm - from sipyco import common_args from artiq import __version__ as artiq_version @@ -70,22 +68,6 @@ class ELFRunner(FileRunner): return f.read() -class LLVMIRRunner(FileRunner): - def compile(self): - with open(self.file, "r") as f: - llmodule = llvm.parse_assembly(f.read()) - llmodule.verify() - return self.target.link([self.target.assemble(llmodule)]) - - -class LLVMBitcodeRunner(FileRunner): - def compile(self): - with open(self.file, "rb") as f: - llmodule = llvm.parse_bitcode(f.read()) - llmodule.verify() - return self.target.link([self.target.assemble(llmodule)]) - - class DummyScheduler: def __init__(self): self.rid = 0 @@ -157,9 +139,7 @@ def _build_experiment(device_mgr, dataset_mgr, args): managers = (device_mgr, dataset_mgr, argument_mgr, {}) if hasattr(args, "file"): is_elf = args.file.endswith(".elf") - is_ll = args.file.endswith(".ll") - is_bc = args.file.endswith(".bc") - if is_elf or is_ll or is_bc: + if is_elf: if args.arguments: raise ValueError("arguments not supported for precompiled kernels") if args.class_name: @@ -167,10 +147,6 @@ def _build_experiment(device_mgr, dataset_mgr, args): "for precompiled kernels") if is_elf: return ELFRunner(managers, file=args.file) - elif is_ll: - return LLVMIRRunner(managers, file=args.file) - elif is_bc: - return LLVMBitcodeRunner(managers, file=args.file) else: import_cache.install_hook() module = file_import(args.file, prefix="artiq_run_") diff --git a/artiq/test/libartiq_support/lib.rs b/artiq/test/libartiq_support/lib.rs deleted file mode 100644 index 8f06852ba..000000000 --- a/artiq/test/libartiq_support/lib.rs +++ /dev/null @@ -1,78 +0,0 @@ -#![feature(libc, panic_unwind, unwind_attributes, rustc_private, int_bits_const)] -#![crate_name = "artiq_support"] -#![crate_type = "cdylib"] - -extern crate std as core; -extern crate libc; -extern crate unwind; - -// Note: this does *not* match the cslice crate! -// ARTIQ Python has the slice length field fixed at 32 bits, even on 64-bit platforms. -mod cslice { - use core::marker::PhantomData; - use core::convert::AsRef; - use core::slice; - - #[repr(C)] - #[derive(Clone, Copy)] - pub struct CSlice<'a, T> { - base: *const T, - len: u32, - phantom: PhantomData<&'a ()> - } - - impl<'a, T> CSlice<'a, T> { - pub fn len(&self) -> usize { - self.len as usize - } - } - - impl<'a, T> AsRef<[T]> for CSlice<'a, T> { - fn as_ref(&self) -> &[T] { - unsafe { - slice::from_raw_parts(self.base, self.len as usize) - } - } - } - - pub trait AsCSlice<'a, T> { - fn as_c_slice(&'a self) -> CSlice<'a, T>; - } - - impl<'a> AsCSlice<'a, u8> for str { - fn as_c_slice(&'a self) -> CSlice<'a, u8> { - CSlice { - base: self.as_ptr(), - len: self.len() as u32, - phantom: PhantomData - } - } - } -} - -#[path = "."] -pub mod eh { - #[path = "../../firmware/libeh/dwarf.rs"] - pub mod dwarf; -} -#[path = "../../firmware/ksupport/eh_artiq.rs"] -pub mod eh_artiq; - -use std::{str, process}; - -fn terminate(exception: &eh_artiq::Exception, mut _backtrace: &mut [usize]) -> ! { - println!("Uncaught {}: {} ({}, {}, {})", - str::from_utf8(exception.name.as_ref()).unwrap(), - str::from_utf8(exception.message.as_ref()).unwrap(), - exception.param[0], - exception.param[1], - exception.param[2]); - println!("at {}:{}:{}", - str::from_utf8(exception.file.as_ref()).unwrap(), - exception.line, - exception.column); - process::exit(1); -} - -#[export_name = "now"] -pub static mut NOW: i64 = 0; diff --git a/artiq/test/lit/codegen/assign_none.py b/artiq/test/lit/codegen/assign_none.py deleted file mode 100644 index 000e87ac7..000000000 --- a/artiq/test/lit/codegen/assign_none.py +++ /dev/null @@ -1,6 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.llvmgen %s - -def f(): - pass -def g(): - a = f() diff --git a/artiq/test/lit/codegen/custom_comparison.py b/artiq/test/lit/codegen/custom_comparison.py deleted file mode 100644 index 8a7a1d32b..000000000 --- a/artiq/test/lit/codegen/custom_comparison.py +++ /dev/null @@ -1,13 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -class Foo: - def __init__(self): - pass - -a = Foo() -b = Foo() - -# CHECK-L: ${LINE:+1}: error: Custom object comparison is not supported -a > b - diff --git a/artiq/test/lit/codegen/custom_inclusion.py b/artiq/test/lit/codegen/custom_inclusion.py deleted file mode 100644 index 92cd1a772..000000000 --- a/artiq/test/lit/codegen/custom_inclusion.py +++ /dev/null @@ -1,13 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -class Foo: - def __init__(self): - pass - -a = Foo() -b = Foo() - -# CHECK-L: ${LINE:+1}: error: Custom object inclusion test is not supported -a in b - diff --git a/artiq/test/lit/codegen/error_illegal_return.py b/artiq/test/lit/codegen/error_illegal_return.py deleted file mode 100644 index 5e15cade7..000000000 --- a/artiq/test/lit/codegen/error_illegal_return.py +++ /dev/null @@ -1,9 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: this function must return a value of type numpy.int32 explicitly -def foo(x): - if x: - return 1 - -foo(True) diff --git a/artiq/test/lit/codegen/none_retval.py b/artiq/test/lit/codegen/none_retval.py deleted file mode 100644 index ed2c9eb25..000000000 --- a/artiq/test/lit/codegen/none_retval.py +++ /dev/null @@ -1,11 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.llvmgen %s - -def make_none(): - return None - -def take_arg(arg): - pass - -def run(): - retval = make_none() - take_arg(retval) diff --git a/artiq/test/lit/codegen/noop_coercion.py b/artiq/test/lit/codegen/noop_coercion.py deleted file mode 100644 index df4ce830b..000000000 --- a/artiq/test/lit/codegen/noop_coercion.py +++ /dev/null @@ -1,4 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.llvmgen %s - -def f(): - return float(1.0) diff --git a/artiq/test/lit/codegen/unreachable_implicit_return.py b/artiq/test/lit/codegen/unreachable_implicit_return.py deleted file mode 100644 index a434f8a28..000000000 --- a/artiq/test/lit/codegen/unreachable_implicit_return.py +++ /dev/null @@ -1,9 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s - -def foo(x): - if x: - return 1 - else: - return 2 - -foo(True) diff --git a/artiq/test/lit/codegen/warning_useless_bool.py b/artiq/test/lit/codegen/warning_useless_bool.py deleted file mode 100644 index d81fa2941..000000000 --- a/artiq/test/lit/codegen/warning_useless_bool.py +++ /dev/null @@ -1,5 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: warning: this expression, which is always truthful, is coerced to bool -bool(IndexError()) diff --git a/artiq/test/lit/constant_hoisting/device_db.py b/artiq/test/lit/constant_hoisting/device_db.py deleted file mode 100644 index e39c83c09..000000000 --- a/artiq/test/lit/constant_hoisting/device_db.py +++ /dev/null @@ -1,8 +0,0 @@ -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": None, "ref_period": 1e-9} - } -} diff --git a/artiq/test/lit/constant_hoisting/invariant_load.py b/artiq/test/lit/constant_hoisting/invariant_load.py deleted file mode 100644 index 62fac4202..000000000 --- a/artiq/test/lit/constant_hoisting/invariant_load.py +++ /dev/null @@ -1,25 +0,0 @@ -# RUN: env ARTIQ_DUMP_IR=%t ARTIQ_IR_NO_LOC=1 %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.txt - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: %LOC.self.FLD.foo = numpy.int32 getattr('foo') %ARG.self -# CHECK-L: for.head: - -class c: - kernel_invariants = {"foo"} - - def __init__(self): - self.foo = 1 - - @kernel - def run(self): - for _ in range(10): - core_log(1.0 * self.foo) - -i = c() - -@kernel -def entrypoint(): - i.run() diff --git a/artiq/test/lit/devirtualization/device_db.py b/artiq/test/lit/devirtualization/device_db.py deleted file mode 100644 index e39c83c09..000000000 --- a/artiq/test/lit/devirtualization/device_db.py +++ /dev/null @@ -1,8 +0,0 @@ -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": None, "ref_period": 1e-9} - } -} diff --git a/artiq/test/lit/devirtualization/function.py b/artiq/test/lit/devirtualization/function.py deleted file mode 100644 index c8fe65691..000000000 --- a/artiq/test/lit/devirtualization/function.py +++ /dev/null @@ -1,23 +0,0 @@ -# RUN: env ARTIQ_DUMP_IR=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.txt -# XFAIL: * - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: call ()->NoneType %local.testbench.entrypoint ; calls testbench.entrypoint - -@kernel -def baz(): - pass - -class foo: - @kernel - def bar(self): - # CHECK-L: call ()->NoneType %local.testbench.baz ; calls testbench.baz - baz() -x = foo() - -@kernel -def entrypoint(): - x.bar() diff --git a/artiq/test/lit/devirtualization/method.py b/artiq/test/lit/devirtualization/method.py deleted file mode 100644 index 8c258a41b..000000000 --- a/artiq/test/lit/devirtualization/method.py +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: env ARTIQ_DUMP_IR=%t %python -m artiq.compiler.testbench.embedding +compile %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t.txt -# XFAIL: * - -from artiq.language.core import * -from artiq.language.types import * - -class foo: - @kernel - def bar(self): - pass -x = foo() - -@kernel -def entrypoint(): - # CHECK-L: ; calls testbench.foo.bar - x.bar() diff --git a/artiq/test/lit/embedding/annotation.py b/artiq/test/lit/embedding/annotation.py deleted file mode 100644 index 21ae25332..000000000 --- a/artiq/test/lit/embedding/annotation.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK: i64 @_Z13testbench.foozz\(i64 %ARG.x, \{ i1, i64 \} %ARG.y\) - -@kernel -def foo(x: TInt64, y: TInt64 = 1) -> TInt64: - print(x+y) - return x+y - -@kernel -def bar(x: TInt64) -> None: - print(x) - -@kernel -def entrypoint(): - print(foo(0, 2)) - print(foo(1, 3)) - bar(3) diff --git a/artiq/test/lit/embedding/array_math_fns.py b/artiq/test/lit/embedding/array_math_fns.py deleted file mode 100644 index d23540b48..000000000 --- a/artiq/test/lit/embedding/array_math_fns.py +++ /dev/null @@ -1,26 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -import numpy as np - -@kernel -def entrypoint(): - # Just make sure everything compiles. - - # LLVM intrinsic: - a = np.array([1.0, 2.0, 3.0]) - b = np.sin(a) - assert b.shape == a.shape - - # libm: - c = np.array([1.0, 2.0, 3.0]) - d = np.arctan(c) - assert d.shape == c.shape - - # libm, binary: - e = np.array([1.0, 2.0, 3.0]) - f = np.array([4.0, 5.0, 6.0]) - g = np.arctan2(e, f) - # g = np.arctan2(e, 0.0) - # g = np.arctan2(0.0, f) - assert g.shape == e.shape diff --git a/artiq/test/lit/embedding/array_transpose.py b/artiq/test/lit/embedding/array_transpose.py deleted file mode 100644 index 2ab44bd7d..000000000 --- a/artiq/test/lit/embedding/array_transpose.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * -import numpy as np - -@kernel -def entrypoint(): - # FIXME: This needs to be a runtime test (but numpy.* integration is - # currently embedding-only). - a = np.array([1, 2, 3]) - b = np.transpose(a) - assert a.shape == b.shape - for i in range(len(a)): - assert a[i] == b[i] - - c = np.array([[1, 2, 3], [4, 5, 6]]) - d = np.transpose(c) - assert c.shape == d.shape - for i in range(2): - for j in range(3): - assert c[i][j] == d[j][i] diff --git a/artiq/test/lit/embedding/arrays.py b/artiq/test/lit/embedding/arrays.py deleted file mode 100644 index 63d846585..000000000 --- a/artiq/test/lit/embedding/arrays.py +++ /dev/null @@ -1,36 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * -from numpy import array - -int_vec = array([1, 2, 3]) -float_vec = array([1.0, 2.0, 3.0]) -int_mat = array([[1, 2], [3, 4]]) -float_mat = array([[1.0, 2.0], [3.0, 4.0]]) - - -@kernel -def entrypoint(): - # TODO: These need to be runtime tests! - assert int_vec.shape == (3, ) - assert int_vec[0] == 1 - assert int_vec[1] == 2 - assert int_vec[2] == 3 - - assert float_vec.shape == (3, ) - assert float_vec[0] == 1.0 - assert float_vec[1] == 2.0 - assert float_vec[2] == 3.0 - - assert int_mat.shape == (2, 2) - assert int_mat[0][0] == 1 - assert int_mat[0][1] == 2 - assert int_mat[1][0] == 3 - assert int_mat[1][1] == 4 - - assert float_mat.shape == (2, 2) - assert float_mat[0][0] == 1.0 - assert float_mat[0][1] == 2.0 - assert float_mat[1][0] == 3.0 - assert float_mat[1][1] == 4.0 diff --git a/artiq/test/lit/embedding/async_rpc.py b/artiq/test/lit/embedding/async_rpc.py deleted file mode 100644 index 47c3041a5..000000000 --- a/artiq/test/lit/embedding/async_rpc.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK: call void @rpc_send_async - -@rpc(flags={"async"}) -def foo(): - pass - -@kernel -def entrypoint(): - foo() diff --git a/artiq/test/lit/embedding/bug_477.py b/artiq/test/lit/embedding/bug_477.py deleted file mode 100644 index 19d496ca6..000000000 --- a/artiq/test/lit/embedding/bug_477.py +++ /dev/null @@ -1,20 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.experiment import * - -class MyClass: - def __init__(self, **kwargs): - for k, v in kwargs.items(): - setattr(self, k, v) - - -sl = [MyClass(x=1), MyClass(x=2)] - -@kernel -def bug(l): - for c in l: - print(c.x) - -@kernel -def entrypoint(): - bug(sl) diff --git a/artiq/test/lit/embedding/class_fn_direct_call.py b/artiq/test/lit/embedding/class_fn_direct_call.py deleted file mode 100644 index 91bdac519..000000000 --- a/artiq/test/lit/embedding/class_fn_direct_call.py +++ /dev/null @@ -1,20 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * - -class C: - @kernel - def f(self): - pass - -class D(C): - @kernel - def f(self): - # super().f() # super() not bound - C.f(self) # KeyError in compile - -di = D() -@kernel -def entrypoint(): - di.f() diff --git a/artiq/test/lit/embedding/device_db.py b/artiq/test/lit/embedding/device_db.py deleted file mode 100644 index e39c83c09..000000000 --- a/artiq/test/lit/embedding/device_db.py +++ /dev/null @@ -1,8 +0,0 @@ -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": None, "ref_period": 1e-9} - } -} diff --git a/artiq/test/lit/embedding/error_attr_absent.py b/artiq/test/lit/embedding/error_attr_absent.py deleted file mode 100644 index 986c5d06a..000000000 --- a/artiq/test/lit/embedding/error_attr_absent.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -class c: - pass - -@kernel -def entrypoint(): - # CHECK-L: :1: error: host object does not have an attribute 'x' - # CHECK-L: ${LINE:+1}: note: expanded from here - a = c - # CHECK-L: ${LINE:+1}: note: attribute accessed here - a.x diff --git a/artiq/test/lit/embedding/error_attr_absent_suggest.py b/artiq/test/lit/embedding/error_attr_absent_suggest.py deleted file mode 100644 index 474a5791a..000000000 --- a/artiq/test/lit/embedding/error_attr_absent_suggest.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -class c: - xx = 1 - -@kernel -def entrypoint(): - # CHECK-L: :1: error: host object does not have an attribute 'x'; did you mean 'xx'? - # CHECK-L: ${LINE:+1}: note: expanded from here - a = c - # CHECK-L: ${LINE:+1}: note: attribute accessed here - a.x diff --git a/artiq/test/lit/embedding/error_attr_conflict.py b/artiq/test/lit/embedding/error_attr_conflict.py deleted file mode 100644 index a8556dd2c..000000000 --- a/artiq/test/lit/embedding/error_attr_conflict.py +++ /dev/null @@ -1,21 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -class c: - pass - -i1 = c() -i1.x = 1 - -i2 = c() -i2.x = 1.0 - -@kernel -def entrypoint(): - # CHECK-L: :1: error: host object has an attribute 'x' of type float, which is different from previously inferred type numpy.int32 for the same attribute - i1.x - # CHECK-L: ${LINE:+1}: note: expanded from here - i2.x diff --git a/artiq/test/lit/embedding/error_attr_constant.py b/artiq/test/lit/embedding/error_attr_constant.py deleted file mode 100644 index d78d4a65c..000000000 --- a/artiq/test/lit/embedding/error_attr_constant.py +++ /dev/null @@ -1,18 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -class c: - kernel_invariants = {"a"} - - def __init__(self): - self.a = 1 - -i = c() - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+1}: error: cannot assign to constant attribute 'a' of class 'testbench.c' - i.a = 1 diff --git a/artiq/test/lit/embedding/error_attr_unify.py b/artiq/test/lit/embedding/error_attr_unify.py deleted file mode 100644 index c8f6321a8..000000000 --- a/artiq/test/lit/embedding/error_attr_unify.py +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -class c: - x = [1, "x"] - -@kernel -def entrypoint(): - # CHECK-L: :1: error: cannot unify numpy.int? with str - # CHECK-NEXT-L: [1, 'x'] - # CHECK-L: ${LINE:+1}: note: expanded from here - a = c - # CHECK-L: ${LINE:+1}: note: while inferring a type for an attribute 'x' of a host object - a.x diff --git a/artiq/test/lit/embedding/error_host_only.py b/artiq/test/lit/embedding/error_host_only.py deleted file mode 100644 index 2e2eba6db..000000000 --- a/artiq/test/lit/embedding/error_host_only.py +++ /dev/null @@ -1,19 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -class foo: - # CHECK-L: ${LINE:+2}: fatal: this function cannot be called as an RPC - @host_only - def pause(self): - pass - -x = foo() - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+2}: note: in function called remotely here - # CHECK-L: ${LINE:+1}: note: while inferring a type for an attribute 'pause' of a host object - x.pause() diff --git a/artiq/test/lit/embedding/error_kernel_method_no_self.py b/artiq/test/lit/embedding/error_kernel_method_no_self.py deleted file mode 100644 index ed129fc39..000000000 --- a/artiq/test/lit/embedding/error_kernel_method_no_self.py +++ /dev/null @@ -1,19 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -class c: - pass -@kernel -def f(): - pass -c.f = f -x = c().f - -@kernel -def entrypoint(): - # CHECK-L: :1: error: function 'f()->NoneType delay('a)' of class 'testbench.c' cannot accept a self argument - # CHECK-L: ${LINE:+1}: note: expanded from here - x diff --git a/artiq/test/lit/embedding/error_kernel_method_self_unify.py b/artiq/test/lit/embedding/error_kernel_method_self_unify.py deleted file mode 100644 index 925ee1d20..000000000 --- a/artiq/test/lit/embedding/error_kernel_method_self_unify.py +++ /dev/null @@ -1,24 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -@kernel -def f(self): - core_log(self.x) -class c: - a = f - x = 1 -class d: - b = f - x = 2 -xa = c().a -xb = d().b - -@kernel -def entrypoint(): - xa() - # CHECK-L: :1: error: cannot unify with %t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -def foo(): - pass - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+1}: fatal: name 'fo0' is not bound to anything; did you mean 'foo'? - fo0() diff --git a/artiq/test/lit/embedding/error_rpc_annot_return.py b/artiq/test/lit/embedding/error_rpc_annot_return.py deleted file mode 100644 index b60709f7c..000000000 --- a/artiq/test/lit/embedding/error_rpc_annot_return.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: ${LINE:+1}: error: type annotation for return type, '1', is not an ARTIQ type -def foo() -> 1: - pass - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+1}: note: in function called remotely here - foo() diff --git a/artiq/test/lit/embedding/error_rpc_async_return.py b/artiq/test/lit/embedding/error_rpc_async_return.py deleted file mode 100644 index 72f3c79c3..000000000 --- a/artiq/test/lit/embedding/error_rpc_async_return.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: ${LINE:+2}: fatal: functions that return a value cannot be defined as async RPCs -@rpc(flags={"async"}) -def foo() -> TInt32: - pass - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+1}: note: function called here - foo() diff --git a/artiq/test/lit/embedding/error_specialized_annot.py b/artiq/test/lit/embedding/error_specialized_annot.py deleted file mode 100644 index 2f5955043..000000000 --- a/artiq/test/lit/embedding/error_specialized_annot.py +++ /dev/null @@ -1,19 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.experiment import * - -class c(): -# CHECK-L: ${LINE:+2}: error: type annotation for argument 'x', '', is not an ARTIQ type - @kernel - def hello(self, x: float): - pass - - @kernel - def run(self): - self.hello(2) - -i = c() -@kernel -def entrypoint(): - i.run() diff --git a/artiq/test/lit/embedding/error_syscall_annot.py b/artiq/test/lit/embedding/error_syscall_annot.py deleted file mode 100644 index 4849910b3..000000000 --- a/artiq/test/lit/embedding/error_syscall_annot.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: ${LINE:+2}: error: type annotation for argument 'x', '1', is not an ARTIQ type -@syscall -def foo(x: 1) -> TNone: - pass - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+1}: note: in system call here - foo() diff --git a/artiq/test/lit/embedding/error_syscall_annot_return.py b/artiq/test/lit/embedding/error_syscall_annot_return.py deleted file mode 100644 index dfc24db9f..000000000 --- a/artiq/test/lit/embedding/error_syscall_annot_return.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: ${LINE:+2}: error: type annotation for return type, '1', is not an ARTIQ type -@syscall -def foo() -> 1: - pass - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+1}: note: in system call here - foo() diff --git a/artiq/test/lit/embedding/error_syscall_arg.py b/artiq/test/lit/embedding/error_syscall_arg.py deleted file mode 100644 index a077e7d57..000000000 --- a/artiq/test/lit/embedding/error_syscall_arg.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: ${LINE:+2}: error: system call argument 'x' must have a type annotation -@syscall -def foo(x) -> TNone: - pass - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+1}: note: in system call here - foo() diff --git a/artiq/test/lit/embedding/error_syscall_default_arg.py b/artiq/test/lit/embedding/error_syscall_default_arg.py deleted file mode 100644 index 0bfdce88a..000000000 --- a/artiq/test/lit/embedding/error_syscall_default_arg.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: ${LINE:+2}: error: system call argument 'x' must not have a default value -@syscall -def foo(x=1) -> TNone: - pass - -@kernel -def entrypoint(): - foo() diff --git a/artiq/test/lit/embedding/error_syscall_return.py b/artiq/test/lit/embedding/error_syscall_return.py deleted file mode 100644 index bad7b20d1..000000000 --- a/artiq/test/lit/embedding/error_syscall_return.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: ${LINE:+2}: error: system call must have a return type annotation -@syscall -def foo(): - pass - -@kernel -def entrypoint(): - foo() diff --git a/artiq/test/lit/embedding/eval.py b/artiq/test/lit/embedding/eval.py deleted file mode 100644 index d2f91cbf9..000000000 --- a/artiq/test/lit/embedding/eval.py +++ /dev/null @@ -1,18 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * - - -def make_incrementer(increment): - return kernel_from_string(["a"], "return a + {}".format(increment), - portable) - - -foo = make_incrementer(1) -bar = make_incrementer(2) - - -@kernel -def entrypoint(): - assert foo(4) == 5 - assert bar(4) == 6 diff --git a/artiq/test/lit/embedding/exception.py b/artiq/test/lit/embedding/exception.py deleted file mode 100644 index 0a0830de4..000000000 --- a/artiq/test/lit/embedding/exception.py +++ /dev/null @@ -1,12 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * -from artiq.coredevice.exceptions import RTIOUnderflow - -@kernel -def entrypoint(): - try: - pass - except RTIOUnderflow: - pass diff --git a/artiq/test/lit/embedding/fast_math_flags.py b/artiq/test/lit/embedding/fast_math_flags.py deleted file mode 100644 index 3ed40f70d..000000000 --- a/artiq/test/lit/embedding/fast_math_flags.py +++ /dev/null @@ -1,20 +0,0 @@ -# RUN: env ARTIQ_DUMP_UNOPT_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t_unopt.ll - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: fmul fast double 1.000000e+00, 0.000000e+00 -@kernel(flags=["fast-math"]) -def foo(): - core_log(1.0 * 0.0) - -# CHECK-L: fmul fast double 2.000000e+00, 0.000000e+00 -@portable(flags=["fast-math"]) -def bar(): - core_log(2.0 * 0.0) - -@kernel -def entrypoint(): - foo() - bar() diff --git a/artiq/test/lit/embedding/fn_ptr_list.py b/artiq/test/lit/embedding/fn_ptr_list.py deleted file mode 100644 index 73e6ad3be..000000000 --- a/artiq/test/lit/embedding/fn_ptr_list.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * - -@kernel -def a(): - pass - -fns = [a, a] - -@kernel -def entrypoint(): - fns[0]() - fns[1]() diff --git a/artiq/test/lit/embedding/function_polymorphism.py b/artiq/test/lit/embedding/function_polymorphism.py deleted file mode 100644 index 52df5ee4f..000000000 --- a/artiq/test/lit/embedding/function_polymorphism.py +++ /dev/null @@ -1,12 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * - -def f(x): - print(x) - -@kernel -def entrypoint(): - f("foo") - f(42) diff --git a/artiq/test/lit/embedding/inheritance.py b/artiq/test/lit/embedding/inheritance.py deleted file mode 100644 index 0863d9163..000000000 --- a/artiq/test/lit/embedding/inheritance.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * - -class a: - @kernel - def f(self): - print(self.x) - return None - -class b(a): - x = 1 -class c(a): - x = 2 - -bi = b() -ci = c() -@kernel -def entrypoint(): - bi.f() - ci.f() diff --git a/artiq/test/lit/embedding/invariant_nested.py b/artiq/test/lit/embedding/invariant_nested.py deleted file mode 100644 index 5957dcb3d..000000000 --- a/artiq/test/lit/embedding/invariant_nested.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * - - -class ClassA: - def __init__(self): - self.foo = False - - -class ClassB: - kernel_invariants = {"bar"} - - def __init__(self): - self.bar = ClassA() - -obj = ClassB() - -@kernel -def entrypoint(): - obj.bar.foo = True diff --git a/artiq/test/lit/embedding/invariant_propagation.py b/artiq/test/lit/embedding/invariant_propagation.py deleted file mode 100644 index e1af5c9c1..000000000 --- a/artiq/test/lit/embedding/invariant_propagation.py +++ /dev/null @@ -1,26 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -class Class: - kernel_invariants = {"foo"} - - def __init__(self): - self.foo = True - - @kernel - def run(self): - if self.foo: - print("bar") - else: - # Make sure all the code for this branch will be completely elided: - # CHECK-NOT: baz - print("baz") - -obj = Class() - -@kernel -def entrypoint(): - obj.run() diff --git a/artiq/test/lit/embedding/math_fns.py b/artiq/test/lit/embedding/math_fns.py deleted file mode 100644 index 6f9416c8d..000000000 --- a/artiq/test/lit/embedding/math_fns.py +++ /dev/null @@ -1,31 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * -import numpy - -@kernel -def entrypoint(): - # LLVM's constant folding for transcendental functions is good enough that - # we can do a basic smoke test by just making sure the module compiles and - # all assertions are statically eliminated. - - # CHECK-NOT: assert - assert numpy.sin(0.0) == 0.0 - assert numpy.cos(0.0) == 1.0 - assert numpy.exp(0.0) == 1.0 - assert numpy.exp2(1.0) == 2.0 - assert numpy.log(numpy.exp(1.0)) == 1.0 - assert numpy.log10(10.0) == 1.0 - assert numpy.log2(2.0) == 1.0 - assert numpy.fabs(-1.0) == 1.0 - assert numpy.floor(42.5) == 42.0 - assert numpy.ceil(42.5) == 43.0 - assert numpy.trunc(41.5) == 41.0 - assert numpy.rint(41.5) == 42.0 - assert numpy.tan(0.0) == 0.0 - assert numpy.arcsin(0.0) == 0.0 - assert numpy.arccos(1.0) == 0.0 - assert numpy.arctan(0.0) == 0.0 - assert numpy.arctan2(0.0, 1.0) == 0.0 diff --git a/artiq/test/lit/embedding/method_on_instance.py b/artiq/test/lit/embedding/method_on_instance.py deleted file mode 100644 index 018545f6b..000000000 --- a/artiq/test/lit/embedding/method_on_instance.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * - -class a: - def foo(self, x): - print(x) - -class b: - def __init__(self): - self.obj = a() - self.meth = self.obj.foo - - @kernel - def run(self): - self.meth(1) - -bi = b() -@kernel -def entrypoint(): - bi.run() diff --git a/artiq/test/lit/embedding/module.py b/artiq/test/lit/embedding/module.py deleted file mode 100644 index d25475b6d..000000000 --- a/artiq/test/lit/embedding/module.py +++ /dev/null @@ -1,11 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * - -import time, os - -@kernel -def entrypoint(): - time.sleep(10) - os.mkdir("foo") diff --git a/artiq/test/lit/embedding/rpc_method_polymorphism.py b/artiq/test/lit/embedding/rpc_method_polymorphism.py deleted file mode 100644 index b7ca9f525..000000000 --- a/artiq/test/lit/embedding/rpc_method_polymorphism.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * - -class c: - def p(self, foo): - print(foo) -i = c() - -@kernel -def entrypoint(): - i.p("foo") - i.p(42) diff --git a/artiq/test/lit/embedding/syscall_flags.py b/artiq/test/lit/embedding/syscall_flags.py deleted file mode 100644 index f8c618c3f..000000000 --- a/artiq/test/lit/embedding/syscall_flags.py +++ /dev/null @@ -1,18 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK: call void @foo\(\)(, !dbg !\d+)? - -# CHECK-L: ; Function Attrs: inaccessiblememonly nounwind -# CHECK-NEXT-L: declare void @foo() - -@syscall(flags={"nounwind", "nowrite"}) -def foo() -> TNone: - pass - -@kernel -def entrypoint(): - foo() diff --git a/artiq/test/lit/embedding/tuple.py b/artiq/test/lit/embedding/tuple.py deleted file mode 100644 index 6f9a14a32..000000000 --- a/artiq/test/lit/embedding/tuple.py +++ /dev/null @@ -1,9 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * - -values = (1, 2) - -@kernel -def entrypoint(): - assert values == (1, 2) diff --git a/artiq/test/lit/embedding/warning_invariant_1.py b/artiq/test/lit/embedding/warning_invariant_1.py deleted file mode 100644 index 5a0b8bdd1..000000000 --- a/artiq/test/lit/embedding/warning_invariant_1.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -class c: - a = b = 0 - def __init__(self, invariants): - self.kernel_invariants = invariants - - def __repr__(self): - return "" - -i1 = c({'a'}) -i2 = c({'a', 'b'}) - -@kernel -def entrypoint(): - # CHECK-L: :1: warning: object of type declares attribute(s) 'b' as kernel invariant, but other objects of the same type do not; the invariant annotation on this object will be ignored - # CHECK-L: ${LINE:+1}: note: expanded from here - [i1, i2] diff --git a/artiq/test/lit/embedding/warning_invariant_2.py b/artiq/test/lit/embedding/warning_invariant_2.py deleted file mode 100644 index b630b21d8..000000000 --- a/artiq/test/lit/embedding/warning_invariant_2.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -class c: - a = b = 0 - def __init__(self, invariants): - self.kernel_invariants = invariants - - def __repr__(self): - return "" - -i1 = c({"a", "b"}) -i2 = c({"a"}) - -@kernel -def entrypoint(): - # CHECK-L: :1: warning: object of type does not declare attribute(s) 'b' as kernel invariant, but other objects of the same type do; the invariant annotation on other objects will be ignored - # CHECK-L: ${LINE:+1}: note: expanded from here - [i1, i2] diff --git a/artiq/test/lit/embedding/warning_invariant_missing.py b/artiq/test/lit/embedding/warning_invariant_missing.py deleted file mode 100644 index 6fc91028f..000000000 --- a/artiq/test/lit/embedding/warning_invariant_missing.py +++ /dev/null @@ -1,20 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -class c: - kernel_invariants = {"a", "b"} - a = 0 - - def __repr__(self): - return "" - -i = c() - -@kernel -def entrypoint(): - # CHECK-L: :1: warning: object of type declares attribute 'b' as kernel invariant, but the instance referenced here does not have this attribute - # CHECK-L: ${LINE:+1}: note: expanded from here - i diff --git a/artiq/test/lit/escape/const_string.py b/artiq/test/lit/escape/const_string.py deleted file mode 100644 index f5c844c05..000000000 --- a/artiq/test/lit/escape/const_string.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.experiment import * - -@kernel -def foo(): - return "x" - -@kernel -def entrypoint(): - foo() - - # Test reassigning strings. - a = "a" - b = a diff --git a/artiq/test/lit/escape/device_db.py b/artiq/test/lit/escape/device_db.py deleted file mode 100644 index e39c83c09..000000000 --- a/artiq/test/lit/escape/device_db.py +++ /dev/null @@ -1,8 +0,0 @@ -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": None, "ref_period": 1e-9} - } -} diff --git a/artiq/test/lit/escape/error_list_aug_asgn.py b/artiq/test/lit/escape/error_list_aug_asgn.py deleted file mode 100644 index 1cdbd8838..000000000 --- a/artiq/test/lit/escape/error_list_aug_asgn.py +++ /dev/null @@ -1,12 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.experiment import * - -@kernel -def entrypoint(): - a = [1,2] - # CHECK-L: ${LINE:+2}: error: lists cannot be mutated in-place - # CHECK-L: ${LINE:+1}: note: try using `a = a + [3,4]` - a += [3,4] - diff --git a/artiq/test/lit/escape/error_mutable_attr.py b/artiq/test/lit/escape/error_mutable_attr.py deleted file mode 100644 index 2d5bc885a..000000000 --- a/artiq/test/lit/escape/error_mutable_attr.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.experiment import * - -class c: - x = [] - -cc = c() - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+1}: error: the assigned value does not outlive the assignment target - cc.x = [1] diff --git a/artiq/test/lit/escape/error_string.py b/artiq/test/lit/escape/error_string.py deleted file mode 100644 index 33fbb71a6..000000000 --- a/artiq/test/lit/escape/error_string.py +++ /dev/null @@ -1,19 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.experiment import * - -@kernel -def foo(): - # CHECK-NOT-L: ${LINE:+1}: error: - return "x" - -@kernel -def bar(): - # CHECK-L: ${LINE:+1}: error: cannot return an allocated value that does not live forever - return "x" + "y" - -@kernel -def entrypoint(): - foo() - bar() diff --git a/artiq/test/lit/exceptions/catch.py b/artiq/test/lit/exceptions/catch.py deleted file mode 100644 index d6c2866c1..000000000 --- a/artiq/test/lit/exceptions/catch.py +++ /dev/null @@ -1,9 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -try: - 1/0 -except ZeroDivisionError: - # CHECK-L: OK - print("OK") diff --git a/artiq/test/lit/exceptions/catch_all.py b/artiq/test/lit/exceptions/catch_all.py deleted file mode 100644 index 1417f5f31..000000000 --- a/artiq/test/lit/exceptions/catch_all.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def catch(f): - try: - f() - except Exception as e: - print(e) - -# CHECK-L: ZeroDivisionError -catch(lambda: 1/0) -# CHECK-L: IndexError -catch(lambda: [1.0][10]) diff --git a/artiq/test/lit/exceptions/catch_multi.py b/artiq/test/lit/exceptions/catch_multi.py deleted file mode 100644 index 472086660..000000000 --- a/artiq/test/lit/exceptions/catch_multi.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def catch(f): - try: - f() - except ZeroDivisionError as zde: - print(zde) - except IndexError as ie: - print(ie) - -# CHECK-L: ZeroDivisionError -catch(lambda: 1/0) -# CHECK-L: IndexError -catch(lambda: [1.0][10]) diff --git a/artiq/test/lit/exceptions/catch_outer.py b/artiq/test/lit/exceptions/catch_outer.py deleted file mode 100644 index de7253eaf..000000000 --- a/artiq/test/lit/exceptions/catch_outer.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def f(): - try: - 1/0 - except ValueError: - # CHECK-NOT-L: FAIL - print("FAIL") - -try: - f() -except ZeroDivisionError: - # CHECK-L: OK - print("OK") diff --git a/artiq/test/lit/exceptions/finally.py b/artiq/test/lit/exceptions/finally.py deleted file mode 100644 index 17304fc15..000000000 --- a/artiq/test/lit/exceptions/finally.py +++ /dev/null @@ -1,21 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def f(): - try: - 1/0 - finally: - print("f-fin") - print("f-out") - -def g(): - try: - f() - except: - print("g-except") - -# CHECK-L: f-fin -# CHECK-NOT-L: f-out -# CHECK-L: g-except -g() diff --git a/artiq/test/lit/exceptions/finally_catch.py b/artiq/test/lit/exceptions/finally_catch.py deleted file mode 100644 index 23bc39730..000000000 --- a/artiq/test/lit/exceptions/finally_catch.py +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def f(): - try: - 1/0 - except: - print("f-except") - finally: - print("f-fin") - print("f-out") - -# CHECK-L: f-except -# CHECK-L: f-fin -# CHECK-L: f-out -f() diff --git a/artiq/test/lit/exceptions/finally_raise.py b/artiq/test/lit/exceptions/finally_raise.py deleted file mode 100644 index 02c41ea7e..000000000 --- a/artiq/test/lit/exceptions/finally_raise.py +++ /dev/null @@ -1,23 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def f(): - try: - 1/0 - finally: - print("f-fin") - raise ValueError() - -def g(): - try: - f() - except ZeroDivisionError: - print("g-except-zde") - except ValueError: - print("g-except-ve") - -# CHECK-L: f-fin -# CHECK-L: g-except-ve -# CHECK-NOT-L: g-except-zde -g() diff --git a/artiq/test/lit/exceptions/finally_reraise.py b/artiq/test/lit/exceptions/finally_reraise.py deleted file mode 100644 index ef4da2af9..000000000 --- a/artiq/test/lit/exceptions/finally_reraise.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -x = 1 - -def doit(): - try: - if x > 0: - raise ZeroDivisionError - r = 0 - finally: - print('final') - return r - -try: - doit() -except ZeroDivisionError: - print('caught') - -# CHECK-L: final -# CHECK-L: caught diff --git a/artiq/test/lit/exceptions/finally_squash.py b/artiq/test/lit/exceptions/finally_squash.py deleted file mode 100644 index 8c7b58fc3..000000000 --- a/artiq/test/lit/exceptions/finally_squash.py +++ /dev/null @@ -1,21 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def f(): - try: - 1/0 - finally: - print("f-fin") - return - -def g(): - try: - f() - except: - print("g-except") - -# CHECK-L: f-fin -# CHECK-NOT-L: f-out -# CHECK-NOT-L: g-except -g() diff --git a/artiq/test/lit/exceptions/finally_uncaught.py b/artiq/test/lit/exceptions/finally_uncaught.py deleted file mode 100644 index 1eb211663..000000000 --- a/artiq/test/lit/exceptions/finally_uncaught.py +++ /dev/null @@ -1,12 +0,0 @@ -# RUN: %not %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def f(): - try: - 1/0 - finally: - print("f-fin") - -# CHECK-L: f-fin -f() diff --git a/artiq/test/lit/exceptions/reraise.py b/artiq/test/lit/exceptions/reraise.py deleted file mode 100644 index 911b22322..000000000 --- a/artiq/test/lit/exceptions/reraise.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %not %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def f(): - # CHECK-L: Uncaught 0:ZeroDivisionError - # CHECK-L: at input.py:${LINE:+1}: - 1/0 - -def g(): - try: - f() - except: - raise - -g() diff --git a/artiq/test/lit/exceptions/reraise_update.py b/artiq/test/lit/exceptions/reraise_update.py deleted file mode 100644 index 11bd30639..000000000 --- a/artiq/test/lit/exceptions/reraise_update.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %not %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def f(): - 1/0 - -def g(): - try: - f() - except Exception as e: - # CHECK-L: Uncaught 0:ZeroDivisionError - # CHECK-L: at input.py:${LINE:+1}: - raise e - -g() diff --git a/artiq/test/lit/exceptions/uncaught.py b/artiq/test/lit/exceptions/uncaught.py deleted file mode 100644 index 13b83ec22..000000000 --- a/artiq/test/lit/exceptions/uncaught.py +++ /dev/null @@ -1,7 +0,0 @@ -# RUN: %not %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -# CHECK-L: Uncaught 0:ZeroDivisionError: cannot divide by zero (0, 0, 0) -# CHECK-L: at input.py:${LINE:+1}: -1/0 diff --git a/artiq/test/lit/inferencer/array_creation.py b/artiq/test/lit/inferencer/array_creation.py deleted file mode 100644 index 824150c22..000000000 --- a/artiq/test/lit/inferencer/array_creation.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: numpy.array(elt='a, num_dims=1) -array([]) -# CHECK-L: numpy.array(elt='b, num_dims=2) -array([[], []]) - -# CHECK-L: numpy.array(elt=numpy.int?, num_dims=1) -array([1, 2, 3]) -# CHECK-L: numpy.array(elt=numpy.int?, num_dims=2) -array([[1, 2, 3], [4, 5, 6]]) - -# Jagged arrays produce runtime failure: -# CHECK-L: numpy.array(elt=numpy.int?, num_dims=2) -array([[1, 2, 3], [4, 5]]) diff --git a/artiq/test/lit/inferencer/builtin_calls.py b/artiq/test/lit/inferencer/builtin_calls.py deleted file mode 100644 index a4b2f81fe..000000000 --- a/artiq/test/lit/inferencer/builtin_calls.py +++ /dev/null @@ -1,38 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: bool:():bool -bool() - -# CHECK-L: bool:([]:list(elt='a)):bool -bool([]) - -# CHECK-L: int:():numpy.int? -int() - -# CHECK-L: int:(1.0:float):numpy.int? -int(1.0) - -# CHECK-L: int64:(1.0:float):numpy.int64 -int64(1.0) - -# CHECK-L: float:():float -float() - -# CHECK-L: float:(1:numpy.int?):float -float(1) - -# CHECK-L: list:():list(elt='b) -list() - -# CHECK-L: len:([]:list(elt='c)):numpy.int32 -len([]) - -# CHECK-L: round:(1.0:float):numpy.int? -round(1.0) - -# CHECK-L: abs:(1:numpy.int?):numpy.int? -abs(1) - -# CHECK-L: abs:(1.0:float):float -abs(1.0) diff --git a/artiq/test/lit/inferencer/cast.py b/artiq/test/lit/inferencer/cast.py deleted file mode 100644 index be2ddbf4a..000000000 --- a/artiq/test/lit/inferencer/cast.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +mono %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: 2:numpy.int64 -int64(2)**32 - -# CHECK-L: round:(1.0:float):numpy.int64 -int64(round(1.0)) diff --git a/artiq/test/lit/inferencer/class.py b/artiq/test/lit/inferencer/class.py deleted file mode 100644 index 4e26b7c58..000000000 --- a/artiq/test/lit/inferencer/class.py +++ /dev/null @@ -1,19 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -class c: - a = 1 - def f(): - pass - def m(self): - pass - -# CHECK-L: c:NoneType delay('a), m: (self:)->NoneType delay('b)}> -c -# CHECK-L: .a:numpy.int? -c.a -# CHECK-L: .f:()->NoneType delay('a) -c.f - -# CHECK-L: .m:method(fn=(self:)->NoneType delay('b), self=) -c().m() diff --git a/artiq/test/lit/inferencer/coerce.py b/artiq/test/lit/inferencer/coerce.py deleted file mode 100644 index 714bf6ad0..000000000 --- a/artiq/test/lit/inferencer/coerce.py +++ /dev/null @@ -1,41 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -1 | 2 -# CHECK-L: 1:numpy.int?:numpy.int? | 2:numpy.int?:numpy.int?:numpy.int? - -1 + 2 -# CHECK-L: 1:numpy.int?:numpy.int? + 2:numpy.int?:numpy.int?:numpy.int? - -(1,) + (2.0,) -# CHECK-L: (1:numpy.int?,):(numpy.int?,) + (2.0:float,):(float,):(numpy.int?, float) - -[1] + [2] -# CHECK-L: [1:numpy.int?]:list(elt=numpy.int?) + [2:numpy.int?]:list(elt=numpy.int?):list(elt=numpy.int?) - -1 * 2 -# CHECK-L: 1:numpy.int?:numpy.int? * 2:numpy.int?:numpy.int?:numpy.int? - -[1] * 2 -# CHECK-L: [1:numpy.int?]:list(elt=numpy.int?) * 2:numpy.int?:list(elt=numpy.int?) - -1 // 2 -# CHECK-L: 1:numpy.int?:numpy.int? // 2:numpy.int?:numpy.int?:numpy.int? - -1 + 1.0 -# CHECK-L: 1:numpy.int?:float + 1.0:float:float - -a = []; a += [1] -# CHECK-L: a:list(elt=numpy.int?) = []:list(elt=numpy.int?); a:list(elt=numpy.int?) += [1:numpy.int?]:list(elt=numpy.int?) - -[] is [1] -# CHECK-L: []:list(elt=numpy.int?) is [1:numpy.int?]:list(elt=numpy.int?):bool - -1 in [1] -# CHECK-L: 1:numpy.int? in [1:numpy.int?]:list(elt=numpy.int?):bool - -[] < [1] -# CHECK-L: []:list(elt=numpy.int?) < [1:numpy.int?]:list(elt=numpy.int?):bool - -1.0 < 1 -# CHECK-L: 1.0:float < 1:numpy.int?:float:bool diff --git a/artiq/test/lit/inferencer/coerce_explicit.py b/artiq/test/lit/inferencer/coerce_explicit.py deleted file mode 100644 index 4455c596c..000000000 --- a/artiq/test/lit/inferencer/coerce_explicit.py +++ /dev/null @@ -1,12 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +mono %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: n:numpy.int32 = -n = 0 -# CHECK-L: a:numpy.int32 = -a = n // 1 -# CHECK-L: b:numpy.int32 = -b = n // 10 -# CHECK-L: q:numpy.int64 = -q = (a << 0) + (b << 8) -core_log(int64(q)) diff --git a/artiq/test/lit/inferencer/error_array.py b/artiq/test/lit/inferencer/error_array.py deleted file mode 100644 index 8099ef9d8..000000000 --- a/artiq/test/lit/inferencer/error_array.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: array cannot be invoked with the arguments () -a = array() - -b = array([1, 2, 3]) - -# CHECK-L: ${LINE:+1}: error: too many indices for array of dimension 1 -b[1, 2] - -# CHECK-L: ${LINE:+1}: error: strided slicing not yet supported for NumPy arrays -b[::-1] - -# CHECK-L: ${LINE:+1}: error: array attributes cannot be assigned to -b.shape = (5, ) diff --git a/artiq/test/lit/inferencer/error_array_augassign.py b/artiq/test/lit/inferencer/error_array_augassign.py deleted file mode 100644 index c868e50c6..000000000 --- a/artiq/test/lit/inferencer/error_array_augassign.py +++ /dev/null @@ -1,11 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -a = array([[1, 2], [3, 4]]) -b = 0.0 - -# CHECK-L: ${LINE:+1}: error: the result of this operation has type numpy.array(elt=float, num_dims=2), which cannot be assigned to a left-hand side of type float -b /= a - -# CHECK-L: ${LINE:+1}: error: the result of this operation has type numpy.array(elt=float, num_dims=2), which cannot be assigned to a left-hand side of type numpy.array(elt=numpy.int?, num_dims=2) -a /= a diff --git a/artiq/test/lit/inferencer/error_array_ops.py b/artiq/test/lit/inferencer/error_array_ops.py deleted file mode 100644 index 4f85290c1..000000000 --- a/artiq/test/lit/inferencer/error_array_ops.py +++ /dev/null @@ -1,12 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -a = array([[1, 2], [3, 4]]) -b = array([7, 8]) - -# NumPy supports implicit broadcasting over axes, which we don't (yet). -# Make sure there is a nice error message. -# CHECK-L: ${LINE:+3}: error: dimensions of '+' array operands must match -# CHECK-L: ${LINE:+2}: note: operand of dimension 2 -# CHECK-L: ${LINE:+1}: note: operand of dimension 1 -a + b diff --git a/artiq/test/lit/inferencer/error_assert.py b/artiq/test/lit/inferencer/error_assert.py deleted file mode 100644 index 1e7c10284..000000000 --- a/artiq/test/lit/inferencer/error_assert.py +++ /dev/null @@ -1,6 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -x = "A" -# CHECK-L: ${LINE:+1}: error: assertion message must be a string literal -assert True, x diff --git a/artiq/test/lit/inferencer/error_builtin_calls.py b/artiq/test/lit/inferencer/error_builtin_calls.py deleted file mode 100644 index 643011f2d..000000000 --- a/artiq/test/lit/inferencer/error_builtin_calls.py +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: the argument of len() must be of an iterable type -len(1) - -# CHECK-L: ${LINE:+1}: error: the argument of list() must be of an iterable type -list(1) - -# CHECK-L: ${LINE:+1}: error: the arguments of min() must be of a numeric type -min([1], [1]) - -# CHECK-L: ${LINE:+1}: error: the arguments of abs() must be of a numeric type -abs([1.0]) - -# CHECK-L: ${LINE:+1}: error: strings currently cannot be constructed -str(1) diff --git a/artiq/test/lit/inferencer/error_bytes_subscript_mut.py b/artiq/test/lit/inferencer/error_bytes_subscript_mut.py deleted file mode 100644 index 96abe780d..000000000 --- a/artiq/test/lit/inferencer/error_bytes_subscript_mut.py +++ /dev/null @@ -1,5 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: type bytes is not mutable -(b"a")[0] = 1 diff --git a/artiq/test/lit/inferencer/error_call.py b/artiq/test/lit/inferencer/error_call.py deleted file mode 100644 index 1497c7821..000000000 --- a/artiq/test/lit/inferencer/error_call.py +++ /dev/null @@ -1,23 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: cannot call this expression of type numpy.int? -(1)() - -def f(x, y, z=1): - pass - -# CHECK-L: ${LINE:+1}: error: variadic arguments are not supported -f(*[]) - -# CHECK-L: ${LINE:+1}: error: variadic arguments are not supported -f(**[]) - -# CHECK-L: ${LINE:+1}: error: the argument 'x' has been passed earlier as positional -f(1, x=1) - -# CHECK-L: ${LINE:+1}: error: mandatory argument 'x' is not passed -f() - -# CHECK: ${LINE:+1}: error: this function of type .* does not accept argument 'q' -f(1, q=1) diff --git a/artiq/test/lit/inferencer/error_class.py b/artiq/test/lit/inferencer/error_class.py deleted file mode 100644 index 0cc075b05..000000000 --- a/artiq/test/lit/inferencer/error_class.py +++ /dev/null @@ -1,10 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: inheritance is not supported -class a(1): - pass - -class b: - # CHECK-L: ${LINE:+1}: fatal: class body must contain only assignments and function definitions - x += 1 diff --git a/artiq/test/lit/inferencer/error_class_redefine.py b/artiq/test/lit/inferencer/error_class_redefine.py deleted file mode 100644 index d5556fd98..000000000 --- a/artiq/test/lit/inferencer/error_class_redefine.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -class c: - pass -# CHECK-L: ${LINE:+1}: fatal: variable 'c' is already defined -class c: - pass diff --git a/artiq/test/lit/inferencer/error_coerce.py b/artiq/test/lit/inferencer/error_coerce.py deleted file mode 100644 index c4f732e7e..000000000 --- a/artiq/test/lit/inferencer/error_coerce.py +++ /dev/null @@ -1,37 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: expected '<<' operand to be of integer type, not float -1 << 2.0 - -# CHECK-L: ${LINE:+3}: error: expected every '+' operand to be a list in this context -# CHECK-L: ${LINE:+2}: note: list of type list(elt=numpy.int?) -# CHECK-L: ${LINE:+1}: note: numpy.int?, which cannot be added to a list -[1] + 2 - -# CHECK-L: ${LINE:+1}: error: cannot unify list(elt=numpy.int?) with list(elt=float): numpy.int? is incompatible with float -[1] + [2.0] - -# CHECK-L: ${LINE:+3}: error: expected every '+' operand to be a tuple in this context -# CHECK-L: ${LINE:+2}: note: tuple of type (numpy.int?,) -# CHECK-L: ${LINE:+1}: note: numpy.int?, which cannot be added to a tuple -(1,) + 2 - -# CHECK-L: ${LINE:+1}: error: passing tuples to '*' is not supported -(1,) * 2 - -# CHECK-L: ${LINE:+3}: error: expected '*' operands to be a list and an integer in this context -# CHECK-L: ${LINE:+2}: note: list operand of type list(elt=numpy.int?) -# CHECK-L: ${LINE:+1}: note: operand of type list(elt='a), which is not a valid repetition amount -[1] * [] - -# CHECK-L: ${LINE:+1}: error: cannot coerce list(elt='a) to a numeric type -[] - 1.0 - -# CHECK-L: ${LINE:+2}: error: the result of this operation has type float, which cannot be assigned to a left-hand side of type numpy.int? -# CHECK-L: ${LINE:+1}: note: expression of type float -a = 1; a += 1.0 - -# CHECK-L: ${LINE:+2}: error: the result of this operation has type (numpy.int?, float), which cannot be assigned to a left-hand side of type (numpy.int?,) -# CHECK-L: ${LINE:+1}: note: expression of type (float,) -b = (1,); b += (1.0,) diff --git a/artiq/test/lit/inferencer/error_comprehension.py b/artiq/test/lit/inferencer/error_comprehension.py deleted file mode 100644 index d586dd657..000000000 --- a/artiq/test/lit/inferencer/error_comprehension.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: if clauses in comprehensions are not supported -[x for x in [] if x] - -# CHECK-L: ${LINE:+1}: error: multiple for clauses in comprehensions are not supported -[(x, y) for x in [] for y in []] diff --git a/artiq/test/lit/inferencer/error_control_flow.py b/artiq/test/lit/inferencer/error_control_flow.py deleted file mode 100644 index 65e300511..000000000 --- a/artiq/test/lit/inferencer/error_control_flow.py +++ /dev/null @@ -1,19 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: return statement outside of a function -return - -# CHECK-L: ${LINE:+1}: error: break statement outside of a loop -break - -# CHECK-L: ${LINE:+1}: error: continue statement outside of a loop -continue - -while True: - def f(): - # CHECK-L: ${LINE:+1}: error: break statement outside of a loop - break - - # CHECK-L: ${LINE:+1}: error: continue statement outside of a loop - continue diff --git a/artiq/test/lit/inferencer/error_exception.py b/artiq/test/lit/inferencer/error_exception.py deleted file mode 100644 index ee049bb2a..000000000 --- a/artiq/test/lit/inferencer/error_exception.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -try: - pass -# CHECK-L: ${LINE:+1}: error: this expression must refer to an exception constructor -except 1: - pass - -try: - pass -# CHECK-L: ${LINE:+1}: error: cannot unify numpy.int? with Exception -except Exception as e: - e = 1 diff --git a/artiq/test/lit/inferencer/error_iterable.py b/artiq/test/lit/inferencer/error_iterable.py deleted file mode 100644 index 73afa2fcc..000000000 --- a/artiq/test/lit/inferencer/error_iterable.py +++ /dev/null @@ -1,5 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: type numpy.int? is not iterable -for x in 1: pass diff --git a/artiq/test/lit/inferencer/error_local_unbound.py b/artiq/test/lit/inferencer/error_local_unbound.py deleted file mode 100644 index 7327a8548..000000000 --- a/artiq/test/lit/inferencer/error_local_unbound.py +++ /dev/null @@ -1,5 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: fatal: undefined variable 'x' -x diff --git a/artiq/test/lit/inferencer/error_locals.py b/artiq/test/lit/inferencer/error_locals.py deleted file mode 100644 index 3a5185ca8..000000000 --- a/artiq/test/lit/inferencer/error_locals.py +++ /dev/null @@ -1,35 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -x = 1 -def a(): - # CHECK-L: ${LINE:+1}: error: cannot declare name 'x' as nonlocal: it is not bound in any outer scope - nonlocal x - -def f(): - y = 1 - def b(): - nonlocal y - # CHECK-L: ${LINE:+1}: error: name 'y' cannot be nonlocal and global simultaneously - global y - - def c(): - global y - # CHECK-L: ${LINE:+1}: error: name 'y' cannot be global and nonlocal simultaneously - nonlocal y - - def d(y): - # CHECK-L: ${LINE:+1}: error: name 'y' cannot be a parameter and global simultaneously - global y - - def e(y): - # CHECK-L: ${LINE:+1}: error: name 'y' cannot be a parameter and nonlocal simultaneously - nonlocal y - -# CHECK-L: ${LINE:+1}: error: duplicate parameter 'x' -def f(x, x): - pass - -# CHECK-L: ${LINE:+1}: error: variadic arguments are not supported -def g(*x): - pass diff --git a/artiq/test/lit/inferencer/error_matmult.py b/artiq/test/lit/inferencer/error_matmult.py deleted file mode 100644 index 2586aec31..000000000 --- a/artiq/test/lit/inferencer/error_matmult.py +++ /dev/null @@ -1,11 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: expected matrix multiplication operand to be of array type -1 @ 2 - -# CHECK-L: ${LINE:+1}: error: expected matrix multiplication operand to be of array type -[1] @ [2] - -# CHECK-L: ${LINE:+1}: error: expected matrix multiplication operand to be 1- or 2-dimensional -array([[[0]]]) @ array([[[1]]]) diff --git a/artiq/test/lit/inferencer/error_method.py b/artiq/test/lit/inferencer/error_method.py deleted file mode 100644 index 2f4d1d3fe..000000000 --- a/artiq/test/lit/inferencer/error_method.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -class c: - def f(): - pass - - def g(self): - pass - -# CHECK-L: ${LINE:+1}: error: function 'f()->NoneType delay('a)' of class 'c' cannot accept a self argument -c().f() - -c.g(1) -# CHECK-L: ${LINE:+1}: error: cannot unify with numpy.int? while inferring the type for self argument -c().g() diff --git a/artiq/test/lit/inferencer/error_return.py b/artiq/test/lit/inferencer/error_return.py deleted file mode 100644 index 40e6fd889..000000000 --- a/artiq/test/lit/inferencer/error_return.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+2}: error: cannot unify numpy.int? with NoneType -# CHECK-L: ${LINE:+1}: note: function with return type numpy.int? -def a(): - return 1 - # CHECK-L: ${LINE:+1}: note: a statement returning NoneType - return - -# CHECK-L: ${LINE:+2}: error: cannot unify numpy.int? with list(elt='a) -# CHECK-L: ${LINE:+1}: note: function with return type numpy.int? -def b(): - return 1 - # CHECK-L: ${LINE:+1}: note: a statement returning list(elt='a) - return [] diff --git a/artiq/test/lit/inferencer/error_str_iter.py b/artiq/test/lit/inferencer/error_str_iter.py deleted file mode 100644 index a79c52f83..000000000 --- a/artiq/test/lit/inferencer/error_str_iter.py +++ /dev/null @@ -1,5 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: type str is not iterable -("a")[0] diff --git a/artiq/test/lit/inferencer/error_subscript.py b/artiq/test/lit/inferencer/error_subscript.py deleted file mode 100644 index d8332ab09..000000000 --- a/artiq/test/lit/inferencer/error_subscript.py +++ /dev/null @@ -1,10 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -x = [] - -# CHECK-L: ${LINE:+1}: error: multi-dimensional indexing only supported for arrays -x[1,2] - -# CHECK-L: ${LINE:+1}: error: multi-dimensional slices are not supported -x[1:2,3:4] diff --git a/artiq/test/lit/inferencer/error_unify.py b/artiq/test/lit/inferencer/error_unify.py deleted file mode 100644 index 636d4f85a..000000000 --- a/artiq/test/lit/inferencer/error_unify.py +++ /dev/null @@ -1,27 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -a = 1 -b = [] - -# CHECK-L: ${LINE:+1}: error: cannot unify numpy.int? with list(elt='a) -a = b - -# CHECK-L: ${LINE:+1}: error: cannot unify numpy.int? with list(elt='a) -[1, []] -# CHECK-L: note: a list element of type numpy.int? -# CHECK-L: note: a list element of type list(elt='a) - -# CHECK-L: ${LINE:+1}: error: cannot unify numpy.int? with bool -1 and False -# CHECK-L: note: an operand of type numpy.int? -# CHECK-L: note: an operand of type bool - -# CHECK-L: ${LINE:+1}: error: expected unary '+' operand to be of numeric type, not list(elt='a) -+[] - -# CHECK-L: ${LINE:+1}: error: expected '~' operand to be of integer type, not float -~1.0 - -# CHECK-L: ${LINE:+1}: error: type numpy.int? does not have an attribute 'x' -(1).x diff --git a/artiq/test/lit/inferencer/error_with_arity.py b/artiq/test/lit/inferencer/error_with_arity.py deleted file mode 100644 index c91a3996b..000000000 --- a/artiq/test/lit/inferencer/error_with_arity.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -class contextmgr: - def __enter__(self, n1): - pass - - def __exit__(self, n1, n2): - pass - -def foo(): - # CHECK-L: ${LINE:+2}: error: function '__enter__(self:, n1:'a)->NoneType delay('b)' must accept 1 positional argument and no optional arguments - # CHECK-L: ${LINE:+1}: error: function '__exit__(self:, n1:'c, n2:'d)->NoneType delay('e)' must accept 4 positional arguments and no optional arguments - with contextmgr(): - pass diff --git a/artiq/test/lit/inferencer/error_with_exn.py b/artiq/test/lit/inferencer/error_with_exn.py deleted file mode 100644 index 283dadb5a..000000000 --- a/artiq/test/lit/inferencer/error_with_exn.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -class contextmgr: - def __enter__(self): - pass - - def __exit__(self, n1, n2, n3): - n3 = 1 - pass - -def foo(): - # CHECK-L: ${LINE:+2}: error: cannot unify numpy.int? with NoneType - # CHECK-L: ${LINE:+1}: note: exception handling via context managers is not supported; the argument 'n3' of function '__exit__(self:, n1:NoneType, n2:NoneType, n3:numpy.int?)->NoneType delay('a)' will always be None - with contextmgr(): - pass diff --git a/artiq/test/lit/inferencer/error_with_many.py b/artiq/test/lit/inferencer/error_with_many.py deleted file mode 100644 index 81dc52017..000000000 --- a/artiq/test/lit/inferencer/error_with_many.py +++ /dev/null @@ -1,6 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: the 'interleave' context manager must be the only one in a 'with' statement -with interleave, sequential: - pass diff --git a/artiq/test/lit/inferencer/error_with_self.py b/artiq/test/lit/inferencer/error_with_self.py deleted file mode 100644 index d22c5c085..000000000 --- a/artiq/test/lit/inferencer/error_with_self.py +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -class contextmgr: - def __enter__(self): - pass - - def __exit__(self, n1, n2, n3): - pass - -def foo(): - contextmgr.__enter__(1) - # CHECK-L: ${LINE:+3}: error: cannot unify with numpy.int? while inferring the type for self argument - # CHECK-L: ${LINE:+2}: note: expression of type - # CHECK-L: ${LINE:+1}: note: reference to an instance with a method '__enter__(self:numpy.int?)->NoneType delay('a)' - with contextmgr(): - pass diff --git a/artiq/test/lit/inferencer/error_with_var.py b/artiq/test/lit/inferencer/error_with_var.py deleted file mode 100644 index 97b1b345a..000000000 --- a/artiq/test/lit/inferencer/error_with_var.py +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -class contextmgr: - def __enter__(self): - return 1 - - def __exit__(self, n1, n2, n3): - pass - -def foo(): - x = "x" - # CHECK-L: ${LINE:+3}: error: cannot unify str with NoneType - # CHECK-L: ${LINE:+2}: note: expression of type str - # CHECK-L: ${LINE:+1}: note: context manager with an '__enter__' method returning NoneType - with contextmgr() as x: - pass diff --git a/artiq/test/lit/inferencer/exception.py b/artiq/test/lit/inferencer/exception.py deleted file mode 100644 index e0e0f9645..000000000 --- a/artiq/test/lit/inferencer/exception.py +++ /dev/null @@ -1,13 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: Exception: -Exception - -try: - pass -except Exception: - pass -except Exception as e: - # CHECK-L: e:Exception - e diff --git a/artiq/test/lit/inferencer/gcd.py b/artiq/test/lit/inferencer/gcd.py deleted file mode 100644 index 3137d7cc0..000000000 --- a/artiq/test/lit/inferencer/gcd.py +++ /dev/null @@ -1,13 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t - -def _gcd(a, b): - if a < 0: - a = -a - while a: - c = a - a = b % a - b = c - return b - -# CHECK-L: _gcd:(a:numpy.int?, b:numpy.int?)->numpy.int?(10:numpy.int?, 25:numpy.int?):numpy.int? -_gcd(10, 25) diff --git a/artiq/test/lit/inferencer/if_expr.py b/artiq/test/lit/inferencer/if_expr.py deleted file mode 100644 index d955bc736..000000000 --- a/artiq/test/lit/inferencer/if_expr.py +++ /dev/null @@ -1,6 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: def foo(val:bool)->numpy.int?: -def foo(val): - return 1 if val else 0 diff --git a/artiq/test/lit/inferencer/matmult.py b/artiq/test/lit/inferencer/matmult.py deleted file mode 100644 index e8e982c57..000000000 --- a/artiq/test/lit/inferencer/matmult.py +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -vec = array([0, 1]) -mat = array([[0, 1], [2, 3]]) - -# CHECK-L: ):numpy.int? -vec @ vec - -# CHECK-L: ):numpy.array(elt=numpy.int?, num_dims=1) -vec @ mat - -# CHECK-L: ):numpy.array(elt=numpy.int?, num_dims=1) -mat @ vec - -# CHECK-L: ):numpy.array(elt=numpy.int?, num_dims=2) -mat @ mat diff --git a/artiq/test/lit/inferencer/prelude.py b/artiq/test/lit/inferencer/prelude.py deleted file mode 100644 index 288cc78b3..000000000 --- a/artiq/test/lit/inferencer/prelude.py +++ /dev/null @@ -1,10 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: x: -x = len - -def f(): - global len - # CHECK-L: len:numpy.int? = - len = 1 diff --git a/artiq/test/lit/inferencer/scoping.py b/artiq/test/lit/inferencer/scoping.py deleted file mode 100644 index 9847ef0ea..000000000 --- a/artiq/test/lit/inferencer/scoping.py +++ /dev/null @@ -1,9 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: []:list(elt=numpy.int?) -x = [] - -def f(): - global x - x[0] = 1 diff --git a/artiq/test/lit/inferencer/slice.py b/artiq/test/lit/inferencer/slice.py deleted file mode 100644 index 610fa9dc3..000000000 --- a/artiq/test/lit/inferencer/slice.py +++ /dev/null @@ -1,6 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -x = [0] -# CHECK-L: [::numpy.int32] -x[:] = [1] diff --git a/artiq/test/lit/inferencer/unify.py b/artiq/test/lit/inferencer/unify.py deleted file mode 100644 index dcff73487..000000000 --- a/artiq/test/lit/inferencer/unify.py +++ /dev/null @@ -1,82 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -a = 1 -# CHECK-L: a:numpy.int? - -b = a -# CHECK-L: b:numpy.int? - -c = True -# CHECK-L: c:bool - -d = False -# CHECK-L: d:bool - -e = None -# CHECK-L: e:NoneType - -f = 1.0 -# CHECK-L: f:float - -g = [] -# CHECK-L: g:list(elt='a) - -h = [1] -# CHECK-L: h:list(elt=numpy.int?) - -i = [] -i[0] = 1 -# CHECK-L: i:list(elt=numpy.int?) - -j = [] -j += [1.0] -# CHECK-L: j:list(elt=float) - -1 if c else 2 -# CHECK-L: 1:numpy.int? if c:bool else 2:numpy.int?:numpy.int? - -True and False -# CHECK-L: True:bool and False:bool:bool - -1 and 0 -# CHECK-L: 1:numpy.int? and 0:numpy.int?:numpy.int? - -~1 -# CHECK-L: 1:numpy.int?:numpy.int? - -not 1 -# CHECK-L: 1:numpy.int?:bool - -[x for x in [1]] -# CHECK-L: [x:numpy.int? for x:numpy.int? in [1:numpy.int?]:list(elt=numpy.int?)]:list(elt=numpy.int?) - -lambda x, y=1: x -# CHECK-L: lambda x:'b, y:numpy.int?=1:numpy.int?: x:'b:(x:'b, ?y:numpy.int?)->'b - -k = "x" -# CHECK-L: k:str - -ka = b"x" -# CHECK-L: ka:bytes - -kb = bytearray(b"x") -# CHECK-L: kb:bytearray - -l = array([1]) -# CHECK-L: l:numpy.array(elt=numpy.int?, num_dims=1) - -IndexError() -# CHECK-L: IndexError:():IndexError - -IndexError("x") -# CHECK-L: IndexError:("x":str):IndexError - -IndexError("x", 1) -# CHECK-L: IndexError:("x":str, 1:numpy.int64):IndexError - -IndexError("x", 1, 1) -# CHECK-L: IndexError:("x":str, 1:numpy.int64, 1:numpy.int64):IndexError - -IndexError("x", 1, 1, 1) -# CHECK-L: IndexError:("x":str, 1:numpy.int64, 1:numpy.int64, 1:numpy.int64):IndexError diff --git a/artiq/test/lit/inferencer/with.py b/artiq/test/lit/inferencer/with.py deleted file mode 100644 index c3128eeef..000000000 --- a/artiq/test/lit/inferencer/with.py +++ /dev/null @@ -1,5 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: as x:NoneType -with interleave as x: pass diff --git a/artiq/test/lit/integration/abs.py b/artiq/test/lit/integration/abs.py deleted file mode 100644 index ba279ab4b..000000000 --- a/artiq/test/lit/integration/abs.py +++ /dev/null @@ -1,7 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -assert abs(1234) == 1234 -assert abs(-1234) == 1234 -assert abs(1234.5) == 1234.5 -assert abs(-1234.5) == 1234.5 diff --git a/artiq/test/lit/integration/arithmetics.py b/artiq/test/lit/integration/arithmetics.py deleted file mode 100644 index 4fee4d27d..000000000 --- a/artiq/test/lit/integration/arithmetics.py +++ /dev/null @@ -1,64 +0,0 @@ -# RUN: %python %s -# RUN: %python -m artiq.compiler.testbench.jit %s -# REQUIRES: exceptions - -assert -(-1) == 1 -assert -(-1.0) == 1.0 -assert +1 == 1 -assert +1.0 == 1.0 -assert 1 + 1 == 2 -assert 1.0 + 1.0 == 2.0 -assert 1 - 1 == 0 -assert 1.0 - 1.0 == 0.0 -assert 2 * 2 == 4 -assert 2.0 * 2.0 == 4.0 -assert 3 / 2 == 1.5 -assert 3.0 / 2.0 == 1.5 -assert 3 // 2 == 1 -assert 3.0 // 2.0 == 1.0 -assert 3 % 2 == 1 -assert -3 % 2 == 1 -assert 3 % -2 == -1 -assert -3 % -2 == -1 -assert -1 % 8 == 7 -#ARTIQ#assert int64(3) % 2 == 1 -#ARTIQ#assert int64(-3) % 2 == 1 -#ARTIQ#assert int64(3) % -2 == -1 -#ARTIQ#assert int64(-3) % -2 == -1 -assert -1 % 8 == 7 -assert 3.0 % 2.0 == 1.0 -assert -3.0 % 2.0 == 1.0 -assert 3.0 % -2.0 == -1.0 -assert -3.0 % -2.0 == -1.0 -assert 3 ** 2 == 9 -assert 3.0 ** 2.0 == 9.0 -assert 9.0 ** 0.5 == 3.0 -assert 1 << 1 == 2 -assert 2 >> 1 == 1 -assert -2 >> 1 == -1 -#ARTIQ#assert 1 << 32 == 0 -assert -1 >> 32 == -1 -assert 0x18 & 0x0f == 0x08 -assert 0x18 | 0x0f == 0x1f -assert 0x18 ^ 0x0f == 0x17 -#ARTIQ#assert ~0x18 == -25 -#ARTIQ#assert ~int64(0x18) == -25 - -try: - 1 / 0 -except ZeroDivisionError: - pass -else: - assert False -try: - 1 // 0 -except ZeroDivisionError: - pass -else: - assert False -try: - 1 % 0 -except ZeroDivisionError: - pass -else: - assert False diff --git a/artiq/test/lit/integration/array_binops.py b/artiq/test/lit/integration/array_binops.py deleted file mode 100644 index cfca32d92..000000000 --- a/artiq/test/lit/integration/array_binops.py +++ /dev/null @@ -1,98 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s - -a = array([1, 2, 3]) -b = array([4, 5, 6]) - -c = a + b -assert c[0] == 5 -assert c[1] == 7 -assert c[2] == 9 - -c += a -assert c[0] == 6 -assert c[1] == 9 -assert c[2] == 12 - -c = b - a -assert c[0] == 3 -assert c[1] == 3 -assert c[2] == 3 - -c -= a -assert c[0] == 2 -assert c[1] == 1 -assert c[2] == 0 - -c = a * b -assert c[0] == 4 -assert c[1] == 10 -assert c[2] == 18 - -c *= a -assert c[0] == 4 -assert c[1] == 20 -assert c[2] == 54 - -c = b // a -assert c[0] == 4 -assert c[1] == 2 -assert c[2] == 2 - -c //= a -assert c[0] == 4 -assert c[1] == 1 -assert c[2] == 0 - -c = a ** b -assert c[0] == 1 -assert c[1] == 32 -assert c[2] == 729 - -c **= a -assert c[0] == 1 -assert c[1] == 1024 -assert c[2] == 387420489 - -c = b % a -assert c[0] == 0 -assert c[1] == 1 -assert c[2] == 0 - -c %= a -assert c[0] == 0 -assert c[1] == 1 -assert c[2] == 0 - -cf = b / a -assert cf[0] == 4.0 -assert cf[1] == 2.5 -assert cf[2] == 2.0 - -cf2 = cf + a -assert cf2[0] == 5.0 -assert cf2[1] == 4.5 -assert cf2[2] == 5.0 - -cf2 += a -assert cf2[0] == 6.0 -assert cf2[1] == 6.5 -assert cf2[2] == 8.0 - -cf /= a -assert cf[0] == 4.0 -assert cf[1] == 1.25 -assert cf[2] == 2.0 / 3.0 - -d = array([[1, 2], [3, 4]]) -e = array([[5, 6], [7, 8]]) -f = d + e -assert f[0][0] == 6 -assert f[0][1] == 8 -assert f[1][0] == 10 -assert f[1][1] == 12 - -f += d -assert f[0][0] == 7 -assert f[0][1] == 10 -assert f[1][0] == 13 -assert f[1][1] == 16 diff --git a/artiq/test/lit/integration/array_broadcast.py b/artiq/test/lit/integration/array_broadcast.py deleted file mode 100644 index d7cbc5998..000000000 --- a/artiq/test/lit/integration/array_broadcast.py +++ /dev/null @@ -1,55 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s - -a = array([1, 2, 3]) - -c = a + 1 -assert c[0] == 2 -assert c[1] == 3 -assert c[2] == 4 - -c = 1 - a -assert c[0] == 0 -assert c[1] == -1 -assert c[2] == -2 - -c = a * 1 -assert c[0] == 1 -assert c[1] == 2 -assert c[2] == 3 - -c = a // 2 -assert c[0] == 0 -assert c[1] == 1 -assert c[2] == 1 - -c = a ** 2 -assert c[0] == 1 -assert c[1] == 4 -assert c[2] == 9 - -c = 2 ** a -assert c[0] == 2 -assert c[1] == 4 -assert c[2] == 8 - -c = a % 2 -assert c[0] == 1 -assert c[1] == 0 -assert c[2] == 1 - -cf = a / 2 -assert cf[0] == 0.5 -assert cf[1] == 1.0 -assert cf[2] == 1.5 - -cf2 = 2 / array([1, 2, 4]) -assert cf2[0] == 2.0 -assert cf2[1] == 1.0 -assert cf2[2] == 0.5 - -d = array([[1, 2], [3, 4]]) -e = d + 1 -assert e[0][0] == 2 -assert e[0][1] == 3 -assert e[1][0] == 4 -assert e[1][1] == 5 diff --git a/artiq/test/lit/integration/array_creation.py b/artiq/test/lit/integration/array_creation.py deleted file mode 100644 index 512382cda..000000000 --- a/artiq/test/lit/integration/array_creation.py +++ /dev/null @@ -1,50 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# REQUIRES: exceptions - -ary = array([1, 2, 3]) -assert len(ary) == 3 -assert ary.shape == (3,) -assert [x * x for x in ary] == [1, 4, 9] - -# Reassign to an existing value to disambiguate type of empty array. -empty_array = array([1]) -empty_array = array([]) -assert len(empty_array) == 0 -assert empty_array.shape == (0,) -assert [x * x for x in empty_array] == [] - -# Creating arrays from generic iterables, rectangularity is assumed (and ensured -# with runtime checks). -list_of_lists = [[1, 2], [3, 4]] -array_of_lists = array(list_of_lists) -assert array_of_lists.shape == (2, 2) -assert [[y for y in x] for x in array_of_lists] == list_of_lists - -matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) -assert len(matrix) == 2 -assert matrix.shape == (2, 3) -# FIXME: Need to decide on a solution for array comparisons — -# NumPy returns an array of bools! -# assert [x for x in matrix] == [array([1.0, 2.0, 3.0]), array([4.0, 5.0, 6.0])] -assert matrix[0, 0] == 1.0 -assert matrix[0, 1] == 2.0 -assert matrix[0, 2] == 3.0 -assert matrix[1, 0] == 4.0 -assert matrix[1, 1] == 5.0 -assert matrix[1, 2] == 6.0 - -matrix[0, 0] = 7.0 -matrix[1, 1] = 8.0 -assert matrix[0, 0] == 7.0 -assert matrix[0, 1] == 2.0 -assert matrix[0, 2] == 3.0 -assert matrix[1, 0] == 4.0 -assert matrix[1, 1] == 8.0 -assert matrix[1, 2] == 6.0 - -array_of_matrices = array([matrix, matrix]) -assert array_of_matrices.shape == (2, 2, 3) - -three_tensor = array([[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]]) -assert len(three_tensor) == 1 -assert three_tensor.shape == (1, 2, 3) diff --git a/artiq/test/lit/integration/array_matmult.py b/artiq/test/lit/integration/array_matmult.py deleted file mode 100644 index 7519c10ff..000000000 --- a/artiq/test/lit/integration/array_matmult.py +++ /dev/null @@ -1,25 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s - -mat23 = array([[1, 2, 3], [4, 5, 6]]) -mat32 = array([[1, 2], [3, 4], [5, 6]]) -vec2 = array([1, 2]) -vec3 = array([1, 2, 3]) - -assert vec3 @ vec3 == 14 - -a = mat23 @ mat32 -assert a.shape == (2, 2) -assert a[0][0] == 22 -assert a[0][1] == 28 -assert a[1][0] == 49 -assert a[1][1] == 64 - -b = mat23 @ vec3 -assert b.shape == (2,) -assert b[0] == 14 -assert b[1] == 32 - -b = vec3 @ mat32 -assert b.shape == (2,) -assert b[0] == 22 -assert b[1] == 28 diff --git a/artiq/test/lit/integration/array_slice.py b/artiq/test/lit/integration/array_slice.py deleted file mode 100644 index 6c37f8366..000000000 --- a/artiq/test/lit/integration/array_slice.py +++ /dev/null @@ -1,24 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s - -a = array([0, 1, 2, 3]) - -b = a[2:3] -assert b.shape == (1,) -assert b[0] == 2 -b[0] = 5 -assert a[2] == 5 - -b = a[3:2] -assert b.shape == (0,) - -c = array([[0, 1], [2, 3]]) - -d = c[:1] -assert d.shape == (1, 2) -assert d[0, 0] == 0 -assert d[0, 1] == 1 -d[0, 0] = 5 -assert c[0, 0] == 5 - -d = c[1:0] -assert d.shape == (0, 2) diff --git a/artiq/test/lit/integration/array_unaryops.py b/artiq/test/lit/integration/array_unaryops.py deleted file mode 100644 index e55b6f733..000000000 --- a/artiq/test/lit/integration/array_unaryops.py +++ /dev/null @@ -1,11 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s - -a = array([1, 2]) - -b = +a -assert b[0] == 1 -assert b[1] == 2 - -b = -a -assert b[0] == -1 -assert b[1] == -2 diff --git a/artiq/test/lit/integration/attribute.py b/artiq/test/lit/integration/attribute.py deleted file mode 100644 index 301243b54..000000000 --- a/artiq/test/lit/integration/attribute.py +++ /dev/null @@ -1,7 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -r = range(10) -assert r.start == 0 -assert r.stop == 10 -assert r.step == 1 diff --git a/artiq/test/lit/integration/bool.py b/artiq/test/lit/integration/bool.py deleted file mode 100644 index 1a68ebd1c..000000000 --- a/artiq/test/lit/integration/bool.py +++ /dev/null @@ -1,21 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -assert (not 0) == True -assert (not 1) == False - -assert (0 and 0) is 0 -assert (1 and 0) is 0 -assert (0 and 1) is 0 -assert (1 and 2) is 2 - -assert (0 or 0) is 0 -assert (1 or 0) is 1 -assert (0 or 1) is 1 -assert (1 or 2) is 1 - -assert bool(False) is False and bool(False) is False -assert bool(0) is False and bool(1) is True -assert bool(0.0) is False and bool(1.0) is True -x = []; assert bool(x) is False; x = [1]; assert bool(x) is True -assert bool(range(0)) is False and bool(range(1)) is True diff --git a/artiq/test/lit/integration/builtin.py b/artiq/test/lit/integration/builtin.py deleted file mode 100644 index 1562edf57..000000000 --- a/artiq/test/lit/integration/builtin.py +++ /dev/null @@ -1,26 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s -# REQUIRES: exceptions - -assert bool() is False -# bool(x) is tested in bool.py - -assert int() is 0 -assert int(1.0) is 1 -#ARTIQ#assert int64(1) << 40 is 1099511627776 - -#ARTIQ#assert float() is 0.0 -#ARTIQ#assert float(1) is 1.0 - -x = list() -if False: x = [1] -assert x == [] - -#ARTIQ#assert range(10) is range(0, 10, 1) -#ARTIQ#assert range(1, 10) is range(1, 10, 1) - -assert len([1, 2, 3]) is 3 -assert len(range(10)) is 10 -assert len(range(0, 10, 2)) is 5 - -#ARTIQ#assert round(1.4) is 1 and round(1.6) is 2 diff --git a/artiq/test/lit/integration/bytes.py b/artiq/test/lit/integration/bytes.py deleted file mode 100644 index da68591e2..000000000 --- a/artiq/test/lit/integration/bytes.py +++ /dev/null @@ -1,5 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -assert b"xy" == b"xy" -assert (b"x" + b"y") == b"xy" diff --git a/artiq/test/lit/integration/class.py b/artiq/test/lit/integration/class.py deleted file mode 100644 index 205210ea0..000000000 --- a/artiq/test/lit/integration/class.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -class c: - a = 1 - def f(): - return 2 - def g(self): - return self.a + 5 - def h(self, x): - return self.a + x - -assert c.a == 1 -assert c.f() == 2 -assert c().g() == 6 -assert c().h(9) == 10 diff --git a/artiq/test/lit/integration/compare.py b/artiq/test/lit/integration/compare.py deleted file mode 100644 index 48a33cc09..000000000 --- a/artiq/test/lit/integration/compare.py +++ /dev/null @@ -1,19 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -assert 1 < 2 and not (2 < 1) -assert 2 > 1 and not (1 > 2) -assert 1 == 1 and not (1 == 2) -assert 1 != 2 and not (1 != 1) -assert 1 <= 1 and 1 <= 2 and not (2 <= 1) -assert 1 >= 1 and 2 >= 1 and not (1 >= 2) -assert 1 is 1 and not (1 is 2) -assert 1 is not 2 and not (1 is not 1) - -x, y = [1], [1] -assert x is x and x is not y -#ARTIQ#assert range(10) is range(10) and range(10) is not range(11) - -lst = [1, 2, 3] -assert 1 in lst and 0 not in lst -assert 1 in range(10) and 11 not in range(10) and -1 not in range(10) diff --git a/artiq/test/lit/integration/finally.py b/artiq/test/lit/integration/finally.py deleted file mode 100644 index e629602ad..000000000 --- a/artiq/test/lit/integration/finally.py +++ /dev/null @@ -1,78 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t.1 -# RUN: OutputCheck %s --file-to-check=%t.1 -# RUN: %python %s >%t.2 -# RUN: OutputCheck %s --file-to-check=%t.2 -# REQUIRES: exceptions - -def f(): - while True: - try: - print("f-try") - break - finally: - print("f-finally") - print("f-out") - -def g(): - x = True - while x: - try: - print("g-try") - x = False - continue - finally: - print("g-finally") - print("g-out") - -def h(): - try: - print("h-try") - return 10 - finally: - print("h-finally") - print("h-out") - return 20 - -def i(): - try: - print("i-try") - return 10 - finally: - print("i-finally") - return 30 - print("i-out") - return 20 - -def j(): - try: - print("j-try") - finally: - print("j-finally") - print("j-out") - -# CHECK-L: f-try -# CHECK-L: f-finally -# CHECK-L: f-out -f() - -# CHECK-L: g-try -# CHECK-L: g-finally -# CHECK-L: g-out -g() - -# CHECK-L: h-try -# CHECK-L: h-finally -# CHECK-NOT-L: h-out -# CHECK-L: h 10 -print("h", h()) - -# CHECK-L: i-try -# CHECK-L: i-finally -# CHECK-NOT-L: i-out -# CHECK-L: i 30 -print("i", i()) - -# CHECK-L: j-try -# CHECK-L: j-finally -# CHECK-L: j-out -print("j", j()) diff --git a/artiq/test/lit/integration/for.py b/artiq/test/lit/integration/for.py deleted file mode 100644 index 7156bee5d..000000000 --- a/artiq/test/lit/integration/for.py +++ /dev/null @@ -1,53 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -count = 0 -for x in range(10): - count += 1 -assert count == 10 - -for x in range(10): - assert True -else: - assert True - -for x in range(0): - assert False -else: - assert True - -for x in range(10): - continue - assert False -else: - assert True - -for x in range(10): - break - assert False -else: - assert False - -# Verify continue target is reset in else block. -cond = False -while True: - if cond: - break - cond = True - for _ in range(1): - pass - else: - continue - assert False -else: - assert False - -# Verify for target is reset in else block. -while True: - for _ in range(1): - pass - else: - break - assert False -else: - assert False diff --git a/artiq/test/lit/integration/function.py b/artiq/test/lit/integration/function.py deleted file mode 100644 index bbaca2083..000000000 --- a/artiq/test/lit/integration/function.py +++ /dev/null @@ -1,11 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -def fib(x): - if x == 1: - return x - else: - return x * fib(x - 1) -assert fib(5) == 120 - -# argument combinations handled in lambda.py diff --git a/artiq/test/lit/integration/if.py b/artiq/test/lit/integration/if.py deleted file mode 100644 index 8d8eec4f2..000000000 --- a/artiq/test/lit/integration/if.py +++ /dev/null @@ -1,27 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -if True: - assert True - -if False: - assert False - -if True: - assert True -else: - assert False - -if False: - assert False -else: - assert True - -assert (0 if True else 1) == 0 -assert (0 if False else 1) == 1 - -if 0: - assert True - -if 1: - assert True diff --git a/artiq/test/lit/integration/instance.py b/artiq/test/lit/integration/instance.py deleted file mode 100644 index 5acea8721..000000000 --- a/artiq/test/lit/integration/instance.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -class c: - a = 1 - -i = c() - -def f(): - c = None - assert i.a == 1 - -assert i.a == 1 -f() diff --git a/artiq/test/lit/integration/lambda.py b/artiq/test/lit/integration/lambda.py deleted file mode 100644 index a1f08763a..000000000 --- a/artiq/test/lit/integration/lambda.py +++ /dev/null @@ -1,10 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -assert (lambda: 1)() == 1 -assert (lambda x: x)(1) == 1 -assert (lambda x, y: x + y)(1, 2) == 3 -assert (lambda x, y=1: x + y)(1) == 2 -assert (lambda x, y=1: x + y)(1, 2) == 3 -assert (lambda x, y=1: x + y)(x=3) == 4 -assert (lambda x, y=1: x + y)(y=2, x=3) == 5 diff --git a/artiq/test/lit/integration/list.py b/artiq/test/lit/integration/list.py deleted file mode 100644 index 97fad6a6c..000000000 --- a/artiq/test/lit/integration/list.py +++ /dev/null @@ -1,19 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s -# REQUIRES: exceptions - -[x, y] = [1, 2] -assert (x, y) == (1, 2) - -lst = [1, 2, 3] -assert [x*x for x in lst] == [1, 4, 9] - -assert [0] == [0] -assert [0] != [1] -assert [[0]] == [[0]] -assert [[0]] != [[1]] -assert [[[0]]] == [[[0]]] -assert [[[0]]] != [[[1]]] - -assert [1] + [2] == [1, 2] -assert [1] * 3 == [1, 1, 1] diff --git a/artiq/test/lit/integration/locals.py b/artiq/test/lit/integration/locals.py deleted file mode 100644 index 6ad9b0763..000000000 --- a/artiq/test/lit/integration/locals.py +++ /dev/null @@ -1,7 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -x = 1 -assert x == 1 -x += 1 -assert x == 2 diff --git a/artiq/test/lit/integration/minmax.py b/artiq/test/lit/integration/minmax.py deleted file mode 100644 index 5f325be7b..000000000 --- a/artiq/test/lit/integration/minmax.py +++ /dev/null @@ -1,7 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -assert min(1, 2) == 1 -assert max(1, 2) == 2 -assert min(1.0, 2.0) == 1.0 -assert max(1.0, 2.0) == 2.0 diff --git a/artiq/test/lit/integration/print.py b/artiq/test/lit/integration/print.py deleted file mode 100644 index 11887bf77..000000000 --- a/artiq/test/lit/integration/print.py +++ /dev/null @@ -1,41 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: None -print(None) - -# CHECK-L: True False -print(True, False) - -# CHECK-L: 1 -1 -print(1, -1) - -# CHECK-L: 10000000000 -print(10000000000) - -# CHECK-L: 1.5 -print(1.5) - -# CHECK-L: (True, 1) -print((True, 1)) - -# CHECK-L: (True,) -print((True,)) - -# CHECK-L: [1, 2, 3] -print([1, 2, 3]) - -# CHECK-L: [[1, 2], [3]] -print([[1, 2], [3]]) - -# CHECK-L: range(0, 10, 1) -print(range(10)) - -# CHECK-L: array([1, 2]) -print(array([1, 2])) - -# CHECK-L: bytes([97, 98]) -print(b"ab") - -# CHECK-L: bytearray([97, 98]) -print(bytearray(b"ab")) diff --git a/artiq/test/lit/integration/raise.py b/artiq/test/lit/integration/raise.py deleted file mode 100644 index 7b9d4fc70..000000000 --- a/artiq/test/lit/integration/raise.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s -# REQUIRES: exceptions - -try: - raise ValueError -except ValueError: - pass diff --git a/artiq/test/lit/integration/str.py b/artiq/test/lit/integration/str.py deleted file mode 100644 index 9d75399e9..000000000 --- a/artiq/test/lit/integration/str.py +++ /dev/null @@ -1,10 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -assert "xy" == "xy" -assert not ("xy" == "xz") - -assert "xy" != "xz" -assert not ("xy" != "xy") - -assert ("x" + "y") == "xy" diff --git a/artiq/test/lit/integration/subscript.py b/artiq/test/lit/integration/subscript.py deleted file mode 100644 index db50809e6..000000000 --- a/artiq/test/lit/integration/subscript.py +++ /dev/null @@ -1,27 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s -# REQUIRES: exceptions - -lst = list(range(10)) -assert lst[0] == 0 -assert lst[1] == 1 -assert lst[-1] == 9 -assert lst[0:1] == [0] -assert lst[0:2] == [0, 1] -assert lst[0:10] == lst -assert lst[1:-1] == lst[1:9] -assert lst[0:1:2] == [0] -assert lst[0:2:2] == [0] -assert lst[0:3:2] == [0, 2] - -lst = [0, 0, 0, 0, 0] -lst[0:5:2] = [1, 2, 3] -assert lst == [1, 0, 2, 0, 3] - -byt = b"abc" -assert byt[0] == 97 -assert byt[1] == 98 - -barr = bytearray(b"abc") -assert barr[0] == 97 -assert barr[1] == 98 diff --git a/artiq/test/lit/integration/tuple.py b/artiq/test/lit/integration/tuple.py deleted file mode 100644 index 44564c151..000000000 --- a/artiq/test/lit/integration/tuple.py +++ /dev/null @@ -1,13 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -x, y = 2, 1 -x, y = y, x -assert x == 1 and y == 2 -assert (1, 2) + (3.0,) == (1, 2, 3.0) - -assert (0,) == (0,) -assert (0,) != (1,) - -assert ([0],) == ([0],) -assert ([0],) != ([1],) diff --git a/artiq/test/lit/integration/while.py b/artiq/test/lit/integration/while.py deleted file mode 100644 index 397055c9a..000000000 --- a/artiq/test/lit/integration/while.py +++ /dev/null @@ -1,62 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -cond, count = True, 0 -while cond: - count += 1 - cond = False -assert count == 1 - -while False: - pass -else: - assert True - -cond = True -while cond: - cond = False -else: - assert True - -while True: - break - assert False -else: - assert False - -cond = True -while cond: - cond = False - continue - assert False - -# Verify continue target is reset in else block. -cond = False -while True: - if cond: - break - cond = True - while False: - assert False - else: - continue - assert False -else: - assert False - -# Verify break target is reset in else block. -while True: - while False: - assert False - else: - break - assert False -else: - assert False - -while 0: - assert False - -while 1: - assert True - break diff --git a/artiq/test/lit/integration/with.py b/artiq/test/lit/integration/with.py deleted file mode 100644 index 8f2b9b9a8..000000000 --- a/artiq/test/lit/integration/with.py +++ /dev/null @@ -1,33 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -class contextmgr: - def __enter__(self): - print(2) - - def __exit__(self, n1, n2, n3): - print(4) - -# CHECK-L: a 1 -# CHECK-L: 2 -# CHECK-L: a 3 -# CHECK-L: 4 -# CHECK-L: a 5 -print("a", 1) -with contextmgr(): - print("a", 3) -print("a", 5) - -# CHECK-L: b 1 -# CHECK-L: 2 -# CHECK-L: 4 -# CHECK-L: b 6 -try: - print("b", 1) - with contextmgr(): - [0][1] - print("b", 3) - print("b", 5) -except: - pass -print("b", 6) diff --git a/artiq/test/lit/interleaving/control_flow.py b/artiq/test/lit/interleaving/control_flow.py deleted file mode 100644 index c4f7356a3..000000000 --- a/artiq/test/lit/interleaving/control_flow.py +++ /dev/null @@ -1,18 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - with interleave: - if True: - print(1) - else: - print(2) - while False: - print(3) - break - delay_mu(1) - print(4) - -# CHECK-L: 1 -# CHECK-L: 4 -f() diff --git a/artiq/test/lit/interleaving/error_inlining.py b/artiq/test/lit/interleaving/error_inlining.py deleted file mode 100644 index dbf237538..000000000 --- a/artiq/test/lit/interleaving/error_inlining.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - delay_mu(2) - -def g(): - delay_mu(2) - -x = f if True else g - -def h(): - with interleave: - f() - # CHECK-L: ${LINE:+1}: fatal: it is not possible to interleave this function call within a 'with interleave:' statement because the compiler could not prove that the same function would always be called - x() diff --git a/artiq/test/lit/interleaving/error_toplevel_control_flow.py b/artiq/test/lit/interleaving/error_toplevel_control_flow.py deleted file mode 100644 index acbb7815e..000000000 --- a/artiq/test/lit/interleaving/error_toplevel_control_flow.py +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - # CHECK-L: ${LINE:+1}: error: cannot interleave this 'with interleave:' statement - with interleave: - # CHECK-L: ${LINE:+1}: note: this 'return' statement transfers control out of the 'with interleave:' statement - return - delay(1.0) - -def g(): - while True: - # CHECK-L: ${LINE:+1}: error: cannot interleave this 'with interleave:' statement - with interleave: - # CHECK-L: ${LINE:+1}: note: this 'break' statement transfers control out of the 'with interleave:' statement - break - delay(1.0) diff --git a/artiq/test/lit/interleaving/indirect.py b/artiq/test/lit/interleaving/indirect.py deleted file mode 100644 index 0f03f55ac..000000000 --- a/artiq/test/lit/interleaving/indirect.py +++ /dev/null @@ -1,28 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - delay_mu(2) - -def g(): - with interleave: - with sequential: - print("A", now_mu()) - f() - # - print("B", now_mu()) - with sequential: - print("C", now_mu()) - f() - # - print("D", now_mu()) - f() - # - print("E", now_mu()) - -# CHECK-L: A 0 -# CHECK-L: C 0 -# CHECK-L: B 2 -# CHECK-L: D 2 -# CHECK-L: E 4 -g() diff --git a/artiq/test/lit/interleaving/indirect_arg.py b/artiq/test/lit/interleaving/indirect_arg.py deleted file mode 100644 index c8df81ba0..000000000 --- a/artiq/test/lit/interleaving/indirect_arg.py +++ /dev/null @@ -1,28 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(n): - delay_mu(n) - -def g(): - with interleave: - with sequential: - print("A", now_mu()) - f(2) - # - print("B", now_mu()) - with sequential: - print("C", now_mu()) - f(2) - # - print("D", now_mu()) - f(2) - # - print("E", now_mu()) - -# CHECK-L: A 0 -# CHECK-L: C 0 -# CHECK-L: B 2 -# CHECK-L: D 2 -# CHECK-L: E 4 -g() diff --git a/artiq/test/lit/interleaving/nonoverlapping.py b/artiq/test/lit/interleaving/nonoverlapping.py deleted file mode 100644 index ffc67326e..000000000 --- a/artiq/test/lit/interleaving/nonoverlapping.py +++ /dev/null @@ -1,25 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def g(): - with interleave: - with sequential: - print("A", now_mu()) - delay_mu(2) - # - print("B", now_mu()) - with sequential: - print("C", now_mu()) - delay_mu(2) - # - print("D", now_mu()) - delay_mu(2) - # - print("E", now_mu()) - -# CHECK-L: A 0 -# CHECK-L: C 0 -# CHECK-L: B 2 -# CHECK-L: D 2 -# CHECK-L: E 4 -g() diff --git a/artiq/test/lit/interleaving/overlapping.py b/artiq/test/lit/interleaving/overlapping.py deleted file mode 100644 index 32914ed1c..000000000 --- a/artiq/test/lit/interleaving/overlapping.py +++ /dev/null @@ -1,25 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def g(): - with interleave: - with sequential: - print("A", now_mu()) - delay_mu(3) - # - print("B", now_mu()) - with sequential: - print("C", now_mu()) - delay_mu(2) - # - print("D", now_mu()) - delay_mu(2) - # - print("E", now_mu()) - -# CHECK-L: A 0 -# CHECK-L: C 0 -# CHECK-L: D 2 -# CHECK-L: B 3 -# CHECK-L: E 4 -g() diff --git a/artiq/test/lit/interleaving/pure_impure_tie.py b/artiq/test/lit/interleaving/pure_impure_tie.py deleted file mode 100644 index b6aca7b81..000000000 --- a/artiq/test/lit/interleaving/pure_impure_tie.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - delay_mu(2) - -def g(): - with interleave: - f() - delay_mu(2) - print(now_mu()) - -# CHECK-L: 2 -g() diff --git a/artiq/test/lit/interleaving/unrolling.py b/artiq/test/lit/interleaving/unrolling.py deleted file mode 100644 index 824032f07..000000000 --- a/artiq/test/lit/interleaving/unrolling.py +++ /dev/null @@ -1,23 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -with interleave: - for x in range(10): - delay_mu(1) - print("a", x) - with sequential: - delay_mu(5) - print("c") - with sequential: - delay_mu(3) - print("b") - -# CHECK-L: a 0 -# CHECK-L: a 1 -# CHECK-L: a 2 -# CHECK-L: b -# CHECK-L: a 3 -# CHECK-L: a 4 -# CHECK-L: c -# CHECK-L: a 5 -# CHECK-L: a 6 diff --git a/artiq/test/lit/iodelay/argument.py b/artiq/test/lit/iodelay/argument.py deleted file mode 100644 index 94da1c764..000000000 --- a/artiq/test/lit/iodelay/argument.py +++ /dev/null @@ -1,7 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: f: (a:float, b:numpy.int64)->NoneType delay(s->mu(a) + b mu) -def f(a, b): - delay(a) - delay_mu(b) diff --git a/artiq/test/lit/iodelay/arith.py b/artiq/test/lit/iodelay/arith.py deleted file mode 100644 index 05d42e666..000000000 --- a/artiq/test/lit/iodelay/arith.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: f: (a:numpy.int32, b:numpy.int32, c:numpy.int32, d:numpy.int32, e:numpy.int32)->NoneType delay(s->mu(a * b // c + d - 10 / e) mu) -def f(a, b, c, d, e): - delay(a * b // c + d - 10 / e) - -f(1,2,3,4,5) diff --git a/artiq/test/lit/iodelay/call.py b/artiq/test/lit/iodelay/call.py deleted file mode 100644 index e08446da1..000000000 --- a/artiq/test/lit/iodelay/call.py +++ /dev/null @@ -1,10 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - delay_mu(1) - -# CHECK-L: g: ()->NoneType delay(2 mu) -def g(): - f() - f() diff --git a/artiq/test/lit/iodelay/call_subst.py b/artiq/test/lit/iodelay/call_subst.py deleted file mode 100644 index fddc007c6..000000000 --- a/artiq/test/lit/iodelay/call_subst.py +++ /dev/null @@ -1,13 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def pulse(len): - # "on" - delay_mu(len) - # "off" - delay_mu(len) - -# CHECK-L: f: ()->NoneType delay(600 mu) -def f(): - pulse(100) - pulse(200) diff --git a/artiq/test/lit/iodelay/class.py b/artiq/test/lit/iodelay/class.py deleted file mode 100644 index 63fab1862..000000000 --- a/artiq/test/lit/iodelay/class.py +++ /dev/null @@ -1,12 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: g: (i:)->NoneType delay(1000000 mu) -def g(i): - i.f(1.0) - -class c: - def f(self, x): - delay(x) - -g(c()) diff --git a/artiq/test/lit/iodelay/error_argument.py b/artiq/test/lit/iodelay/error_argument.py deleted file mode 100644 index f92dd559d..000000000 --- a/artiq/test/lit/iodelay/error_argument.py +++ /dev/null @@ -1,12 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(x): - delay_mu(x) - -x = 1 - -def g(): - # CHECK-L: ${LINE:+2}: error: call cannot be interleaved because an argument cannot be statically evaluated - # CHECK-L: ${LINE:+1}: note: this expression is not supported in the expression for argument 'x' that affects I/O delay - f(x if True else x) diff --git a/artiq/test/lit/iodelay/error_arith.py b/artiq/test/lit/iodelay/error_arith.py deleted file mode 100644 index 6a4c9f0c1..000000000 --- a/artiq/test/lit/iodelay/error_arith.py +++ /dev/null @@ -1,21 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(a): - b = 1.0 - # CHECK-L: ${LINE:+3}: error: call cannot be interleaved - # CHECK-L: ${LINE:+2}: note: this variable is not an argument of the innermost function - # CHECK-L: ${LINE:-4}: note: only these arguments are in scope of analysis - delay(b) - -def g(): - # CHECK-L: ${LINE:+2}: error: call cannot be interleaved - # CHECK-L: ${LINE:+1}: note: this operator is not supported as an argument for delay() - delay(2.0**2) - -def h(): - # CHECK-L: ${LINE:+2}: error: call cannot be interleaved - # CHECK-L: ${LINE:+1}: note: this expression is not supported as an argument for delay_mu() - delay_mu(1 if False else 2) - -f(1) diff --git a/artiq/test/lit/iodelay/error_bad_interleave.py b/artiq/test/lit/iodelay/error_bad_interleave.py deleted file mode 100644 index b368c28f3..000000000 --- a/artiq/test/lit/iodelay/error_bad_interleave.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - with interleave: - # CHECK-L: ${LINE:+1}: error: while statement cannot be interleaved - while True: - delay_mu(1) diff --git a/artiq/test/lit/iodelay/error_builtinfn.py b/artiq/test/lit/iodelay/error_builtinfn.py deleted file mode 100644 index b1b89a78f..000000000 --- a/artiq/test/lit/iodelay/error_builtinfn.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - x = 1 - # CHECK-L: ${LINE:+1}: error: call cannot be interleaved because an argument cannot be statically evaluated - delay_mu(x) - -def g(): - x = 1.0 - # CHECK-L: ${LINE:+1}: error: call cannot be interleaved - delay(x) - - diff --git a/artiq/test/lit/iodelay/error_call_nested.py b/artiq/test/lit/iodelay/error_call_nested.py deleted file mode 100644 index 2c12af9bd..000000000 --- a/artiq/test/lit/iodelay/error_call_nested.py +++ /dev/null @@ -1,11 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - # CHECK-L: ${LINE:+1}: error: call cannot be interleaved - delay(1.0**2) - -def g(): - # CHECK-L: ${LINE:+1}: note: function called here - f() - f() diff --git a/artiq/test/lit/iodelay/error_call_subst.py b/artiq/test/lit/iodelay/error_call_subst.py deleted file mode 100644 index 0d1ba0843..000000000 --- a/artiq/test/lit/iodelay/error_call_subst.py +++ /dev/null @@ -1,13 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def pulse(len): - # "on" - delay_mu(len) - # "off" - delay_mu(len) - -def f(): - a = 100 - # CHECK-L: ${LINE:+1}: error: call cannot be interleaved - pulse(a) diff --git a/artiq/test/lit/iodelay/error_control_flow.py b/artiq/test/lit/iodelay/error_control_flow.py deleted file mode 100644 index c179c95b9..000000000 --- a/artiq/test/lit/iodelay/error_control_flow.py +++ /dev/null @@ -1,23 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - # CHECK-L: ${LINE:+1}: error: while statement cannot be interleaved - while True: - delay_mu(1) - -def g(): - # CHECK-L: ${LINE:+1}: error: if statement cannot be interleaved - if True: - delay_mu(1) - -def h(): - # CHECK-L: ${LINE:+1}: error: if expression cannot be interleaved - delay_mu(1) if True else delay_mu(2) - -def i(): - # CHECK-L: ${LINE:+1}: error: try statement cannot be interleaved - try: - delay_mu(1) - finally: - pass diff --git a/artiq/test/lit/iodelay/error_for.py b/artiq/test/lit/iodelay/error_for.py deleted file mode 100644 index aae5d47f3..000000000 --- a/artiq/test/lit/iodelay/error_for.py +++ /dev/null @@ -1,9 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - r = range(10) - # CHECK-L: ${LINE:+2}: error: for statement cannot be interleaved because iteration count is indeterminate - # CHECK-L: ${LINE:+1}: note: this value is not a constant range literal - for _ in r: - delay_mu(1) diff --git a/artiq/test/lit/iodelay/error_goto.py b/artiq/test/lit/iodelay/error_goto.py deleted file mode 100644 index 714db7610..000000000 --- a/artiq/test/lit/iodelay/error_goto.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - for _ in range(10): - delay_mu(10) - # CHECK-L: ${LINE:+1}: error: loop iteration count is indeterminate because of control flow - break - -def g(): - for _ in range(10): - delay_mu(10) - # CHECK-L: ${LINE:+1}: error: loop iteration count is indeterminate because of control flow - continue diff --git a/artiq/test/lit/iodelay/error_iterable.py b/artiq/test/lit/iodelay/error_iterable.py deleted file mode 100644 index 6429236db..000000000 --- a/artiq/test/lit/iodelay/error_iterable.py +++ /dev/null @@ -1,10 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -x = 1 - -def f(): - # CHECK-L: ${LINE:+2}: error: for statement cannot be interleaved because iteration count is indeterminate - # CHECK-L: ${LINE:+1}: note: this expression is not supported in an iterable used in a for loop that is being interleaved - for _ in range(x if True else x): - delay_mu(10) diff --git a/artiq/test/lit/iodelay/error_return.py b/artiq/test/lit/iodelay/error_return.py deleted file mode 100644 index c047de2b0..000000000 --- a/artiq/test/lit/iodelay/error_return.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - if True: - # CHECK-L: ${LINE:+1}: error: only return statement at the end of the function can be interleaved - return 1 - delay_mu(1) diff --git a/artiq/test/lit/iodelay/error_unify.py b/artiq/test/lit/iodelay/error_unify.py deleted file mode 100644 index 723b5e393..000000000 --- a/artiq/test/lit/iodelay/error_unify.py +++ /dev/null @@ -1,11 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(): - delay_mu(10) - -# CHECK-L: ${LINE:+1}: fatal: delay delay(20 mu) was inferred for this function, but its delay is already constrained externally to delay(10 mu) -def g(): - delay_mu(20) - -x = f if True else g diff --git a/artiq/test/lit/iodelay/goto.py b/artiq/test/lit/iodelay/goto.py deleted file mode 100644 index d80de43f9..000000000 --- a/artiq/test/lit/iodelay/goto.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: f: ()->NoneType delay(10 mu) -def f(): - delay_mu(10) - for _ in range(10): - break - -# CHECK-L: g: ()->NoneType delay(10 mu) -def g(): - delay_mu(10) - for _ in range(10): - continue diff --git a/artiq/test/lit/iodelay/interleave.py b/artiq/test/lit/iodelay/interleave.py deleted file mode 100644 index 76e30b7a7..000000000 --- a/artiq/test/lit/iodelay/interleave.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: f: (a:numpy.int64, b:numpy.int64)->NoneType delay(max(a, b) mu) -def f(a, b): - with interleave: - delay_mu(a) - delay_mu(b) - -# CHECK-L: g: (a:numpy.int64)->NoneType delay(max(a, 200) mu) -def g(a): - with interleave: - delay_mu(100) - delay_mu(200) - delay_mu(a) diff --git a/artiq/test/lit/iodelay/linear.py b/artiq/test/lit/iodelay/linear.py deleted file mode 100644 index cb2bed204..000000000 --- a/artiq/test/lit/iodelay/linear.py +++ /dev/null @@ -1,12 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: f: ()->NoneType delay(1001000 mu) -def f(): - delay(1.0) - delay_mu(1000) - -# CHECK-L: g: ()->NoneType delay(3 mu) -def g(): - delay_mu(1) - delay_mu(2) diff --git a/artiq/test/lit/iodelay/loop.py b/artiq/test/lit/iodelay/loop.py deleted file mode 100644 index 37bcb9e07..000000000 --- a/artiq/test/lit/iodelay/loop.py +++ /dev/null @@ -1,13 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: f: ()->NoneType delay(30 mu) -def f(): - for _ in range(10): - delay_mu(3) - -# CHECK-L: g: ()->NoneType delay(60 mu) -def g(): - for _ in range(10): - for _ in range(2): - delay_mu(3) diff --git a/artiq/test/lit/iodelay/order_invariance.py b/artiq/test/lit/iodelay/order_invariance.py deleted file mode 100644 index e4deb96c5..000000000 --- a/artiq/test/lit/iodelay/order_invariance.py +++ /dev/null @@ -1,10 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: g: ()->NoneType delay(2 mu) -def g(): - f() - f() - -def f(): - delay_mu(1) diff --git a/artiq/test/lit/iodelay/range.py b/artiq/test/lit/iodelay/range.py deleted file mode 100644 index c5592927e..000000000 --- a/artiq/test/lit/iodelay/range.py +++ /dev/null @@ -1,21 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: f: (a:numpy.int32)->NoneType delay(3 * a mu) -def f(a): - for _ in range(a): - delay_mu(3) - -# CHECK-L: g: (a:numpy.int32, b:numpy.int32)->NoneType delay(3 * (b - a) mu) -def g(a, b): - for _ in range(a, b): - delay_mu(3) - -# CHECK-L: h: (a:numpy.int32, b:numpy.int32, c:numpy.int32)->NoneType delay(3 * (b - a) // c mu) -def h(a, b, c): - for _ in range(a, b, c): - delay_mu(3) - -f(1) -g(1,2) -h(1,2,3) diff --git a/artiq/test/lit/iodelay/return.py b/artiq/test/lit/iodelay/return.py deleted file mode 100644 index 9eefe1f54..000000000 --- a/artiq/test/lit/iodelay/return.py +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: f: ()->numpy.int32 delay(30 mu) -def f(): - for _ in range(10): - delay_mu(3) - return 10 - -# CHECK-L: g: (x:float)->numpy.int32 -# CHECK-NOT-L: delay -def g(x): - if x > 1.0: - return 1 - return 0 - -g(1.0) diff --git a/artiq/test/lit/iodelay/sequential.py b/artiq/test/lit/iodelay/sequential.py deleted file mode 100644 index 5be751126..000000000 --- a/artiq/test/lit/iodelay/sequential.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: f: (a:numpy.int64, b:numpy.int64)->NoneType delay(a + b mu) -def f(a, b): - with sequential: - delay_mu(a) - delay_mu(b) diff --git a/artiq/test/lit/lit.cfg b/artiq/test/lit/lit.cfg deleted file mode 100644 index 693383297..000000000 --- a/artiq/test/lit/lit.cfg +++ /dev/null @@ -1,33 +0,0 @@ -# -*- python -*- - -import os -import sys -import lit.util -import lit.formats - -root = os.path.join(os.path.dirname(__file__), "..") - -config.name = "ARTIQ" -config.test_format = lit.formats.ShTest() -config.suffixes = [".py"] -config.excludes = ["not.py", "device_db.py"] - -if os.getenv("COVERAGE"): - config.environment["COVERAGE_FILE"] = os.path.join(root, "..", ".coverage") - python = "coverage run --parallel-mode --source=artiq" -else: - python = sys.executable -config.substitutions.append( ("%python", python) ) - -if os.getenv("PYTHONPATH"): - config.environment["PYTHONPATH"] = os.getenv("PYTHONPATH") - -not_ = "{} {}".format(sys.executable, os.path.join(root, "lit", "not.py")) -config.substitutions.append( ("%not", not_) ) - -if os.name == "posix": - config.environment["LIBARTIQ_SUPPORT"] = os.getenv("LIBARTIQ_SUPPORT") - config.environment["RUST_BACKTRACE"] = "1" - - config.available_features.add("exceptions") - config.available_features.add("time") diff --git a/artiq/test/lit/local_access/invalid_closure.py b/artiq/test/lit/local_access/invalid_closure.py deleted file mode 100644 index 75948fb57..000000000 --- a/artiq/test/lit/local_access/invalid_closure.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -if False: - t = 1 - -# CHECK-L: ${LINE:+1}: error: variable 't' can be captured in a closure uninitialized -l = lambda: t - -# CHECK-L: ${LINE:+1}: error: variable 't' can be captured in a closure uninitialized -def f(): - return t - -l() -f() diff --git a/artiq/test/lit/local_access/invalid_flow.py b/artiq/test/lit/local_access/invalid_flow.py deleted file mode 100644 index 7b99958b4..000000000 --- a/artiq/test/lit/local_access/invalid_flow.py +++ /dev/null @@ -1,20 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -x = 1 -if x > 10: - y = 1 -# CHECK-L: ${LINE:+1}: error: variable 'y' is not always initialized -x + y - -for z in [1]: - pass -# CHECK-L: ${LINE:+1}: error: variable 'z' is not always initialized --z - -if True: - pass -else: - t = 1 -# CHECK-L: ${LINE:+1}: error: variable 't' is not always initialized --t diff --git a/artiq/test/lit/local_access/multiple_asgn.py b/artiq/test/lit/local_access/multiple_asgn.py deleted file mode 100644 index b316a2005..000000000 --- a/artiq/test/lit/local_access/multiple_asgn.py +++ /dev/null @@ -1,5 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s - -def f(): - x, y = [0], [0] - x[0], y[0] diff --git a/artiq/test/lit/local_access/parallel.py b/artiq/test/lit/local_access/parallel.py deleted file mode 100644 index 001049117..000000000 --- a/artiq/test/lit/local_access/parallel.py +++ /dev/null @@ -1,6 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t - -with interleave: - delay(1.0) - t0 = now_mu() -print(t0) diff --git a/artiq/test/lit/local_access/valid.py b/artiq/test/lit/local_access/valid.py deleted file mode 100644 index 3c5fd0208..000000000 --- a/artiq/test/lit/local_access/valid.py +++ /dev/null @@ -1,7 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t - -if False: - x = 1 -else: - x = 2 --x diff --git a/artiq/test/lit/local_demotion/closure.py b/artiq/test/lit/local_demotion/closure.py deleted file mode 100644 index 5786eb20e..000000000 --- a/artiq/test/lit/local_demotion/closure.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.irgen %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def x(y): pass - -# CHECK-L: NoneType input.a(environment(...) %ARG.ENV, NoneType %ARG.self) { -# CHECK-L: setlocal('self') %ENV, NoneType %ARG.self -# CHECK-NOT-L: call (y:NoneType)->NoneType %LOC.x, NoneType %ARG.self - -def a(self): - def b(): - pass - x(self) - -a(None) diff --git a/artiq/test/lit/local_demotion/demotion.py b/artiq/test/lit/local_demotion/demotion.py deleted file mode 100644 index c9b4ed0c5..000000000 --- a/artiq/test/lit/local_demotion/demotion.py +++ /dev/null @@ -1,13 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.irgen %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def x(y): pass - -# CHECK-L: NoneType input.a(environment(...) %ARG.ENV, NoneType %ARG.self) { -# CHECK-NOT-L: getlocal('self') %ENV -# CHECK-L: call (y:NoneType)->NoneType %LOC.x, NoneType %ARG.self - -def a(self): - x(self) - -a(None) diff --git a/artiq/test/lit/monomorphism/bug_1242.py b/artiq/test/lit/monomorphism/bug_1242.py deleted file mode 100644 index 8918a30cc..000000000 --- a/artiq/test/lit/monomorphism/bug_1242.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -x = 0x100000000 -# CHECK-L: x: numpy.int64 - -y = int32(x) -# CHECK-L: y: numpy.int32 diff --git a/artiq/test/lit/monomorphism/bug_1252.py b/artiq/test/lit/monomorphism/bug_1252.py deleted file mode 100644 index e00a899ab..000000000 --- a/artiq/test/lit/monomorphism/bug_1252.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.irgen %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: %BLT.round = numpy.int64 builtin(round) float -def frequency_to_ftw(frequency): - return int64(round(1e-9*frequency)) - -frequency_to_ftw(1e9) diff --git a/artiq/test/lit/monomorphism/coercion.py b/artiq/test/lit/monomorphism/coercion.py deleted file mode 100644 index bbd67e936..000000000 --- a/artiq/test/lit/monomorphism/coercion.py +++ /dev/null @@ -1,10 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -def f(x): - x = int64(0) - return x - -# CHECK-L: g: ()->numpy.int64 -def g(): - return f(1 + 0) diff --git a/artiq/test/lit/monomorphism/integers.py b/artiq/test/lit/monomorphism/integers.py deleted file mode 100644 index e6760fffb..000000000 --- a/artiq/test/lit/monomorphism/integers.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -x = 1 -# CHECK-L: x: numpy.int32 - -y = int(1) -# CHECK-L: y: numpy.int32 diff --git a/artiq/test/lit/monomorphism/round.py b/artiq/test/lit/monomorphism/round.py deleted file mode 100644 index 74df18401..000000000 --- a/artiq/test/lit/monomorphism/round.py +++ /dev/null @@ -1,11 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +mono %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: round:(1.0:float):numpy.int32 -round(1.0) - -# CHECK-L: round:(2.0:float):numpy.int32 -int32(round(2.0)) - -# CHECK-L: round:(3.0:float):numpy.int64 -int64(round(3.0)) diff --git a/artiq/test/lit/not.py b/artiq/test/lit/not.py deleted file mode 100644 index 855a36416..000000000 --- a/artiq/test/lit/not.py +++ /dev/null @@ -1,7 +0,0 @@ -import sys, subprocess - -def main(): - exit(not subprocess.call(sys.argv[1:])) - -if __name__ == "__main__": - main() diff --git a/artiq/test/lit/regression/bug_659.py b/artiq/test/lit/regression/bug_659.py deleted file mode 100644 index 096839725..000000000 --- a/artiq/test/lit/regression/bug_659.py +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * -import numpy as np - -@kernel -def rotate(array): - '''Rotates an array, deleting the oldest value''' - length = len(array) - for i in range(np.int64(len(array)) - 1): - array[length - i - 1] = array[length - i - 2] - array[0] = 0 - -@kernel -def entrypoint(): - rotate([1,2,3,4]) diff --git a/artiq/test/lit/regression/device_db.py b/artiq/test/lit/regression/device_db.py deleted file mode 100644 index e39c83c09..000000000 --- a/artiq/test/lit/regression/device_db.py +++ /dev/null @@ -1,8 +0,0 @@ -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": None, "ref_period": 1e-9} - } -} diff --git a/artiq/test/lit/regression/issue_1506.py b/artiq/test/lit/regression/issue_1506.py deleted file mode 100644 index 88d8831bd..000000000 --- a/artiq/test/lit/regression/issue_1506.py +++ /dev/null @@ -1,44 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s - -# -# Check various sret-ized return types integrate properly with try/finally, which lowers -# to `invoke` on the LLVM level (code adapted from GitHub #1506). -# - -LIST = [1, 2] - - -def get_tuple(): - return (1, 2) - - -def get_list(): - return LIST - - -def get_range(): - return range(10) - - -def main(): - try: - a, b = get_tuple() - assert a == 1 - assert b == 2 - finally: - pass - - try: - for _ in get_list(): - pass - finally: - pass - - try: - for _ in get_range(): - pass - finally: - pass - - -main() diff --git a/artiq/test/lit/regression/issue_1627.py b/artiq/test/lit/regression/issue_1627.py deleted file mode 100644 index 828ef3a9f..000000000 --- a/artiq/test/lit/regression/issue_1627.py +++ /dev/null @@ -1,13 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * -import numpy as np - -n = 2 -data = np.zeros((n, n)) - - -@kernel -def entrypoint(): - print(data[:n]) diff --git a/artiq/test/lit/regression/issue_1632.py b/artiq/test/lit/regression/issue_1632.py deleted file mode 100644 index c7f36f96b..000000000 --- a/artiq/test/lit/regression/issue_1632.py +++ /dev/null @@ -1,19 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * -import numpy as np - -class A: - def __init__(self): - self.n = 2 - - @kernel - def run(self): - print([1, 2, 3][:self.n]) - -a = A() - -@kernel -def entrypoint(): - a.run() diff --git a/artiq/test/lit/time/advance.py b/artiq/test/lit/time/advance.py deleted file mode 100644 index 7a6a894aa..000000000 --- a/artiq/test/lit/time/advance.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# REQUIRES: time - -assert now_mu() == 0 -delay(100.0) -assert now_mu() == 100000000 -at_mu(12345000000) -assert now_mu() == 12345000000 diff --git a/artiq/test/lit/time/advance_mu.py b/artiq/test/lit/time/advance_mu.py deleted file mode 100644 index d674afbec..000000000 --- a/artiq/test/lit/time/advance_mu.py +++ /dev/null @@ -1,8 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# REQUIRES: time - -assert now_mu() == 0 -delay_mu(100) -assert now_mu() == 100 -at_mu(12345) -assert now_mu() == 12345 diff --git a/artiq/test/lit/time/parallel.py b/artiq/test/lit/time/parallel.py deleted file mode 100644 index c54261f48..000000000 --- a/artiq/test/lit/time/parallel.py +++ /dev/null @@ -1,18 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# REQUIRES: time - -with parallel: - with sequential: - assert now_mu() == 0 - delay_mu(10) - assert now_mu() == 10 - with sequential: - assert now_mu() == 0 - delay_mu(20) - assert now_mu() == 20 - with sequential: - assert now_mu() == 0 - delay_mu(15) - assert now_mu() == 15 - assert now_mu() == 0 -assert now_mu() == 20 diff --git a/doc/manual/conf.py b/doc/manual/conf.py index bc092928f..ad0a85689 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -37,7 +37,7 @@ mock_modules = ["artiq.gui.waitingspinnerwidget", "qasync", "pyqtgraph", "matplotlib", "numpy", "dateutil", "dateutil.parser", "prettytable", "PyQt5", "h5py", "serial", "scipy", "scipy.interpolate", - "llvmlite", "Levenshtein", "pythonparser", + "nac3artiq", "sipyco", "sipyco.pc_rpc", "sipyco.sync_struct", "sipyco.asyncio_tools", "sipyco.logging_tools", "sipyco.broadcast", "sipyco.packed_exceptions"] diff --git a/flake.lock b/flake.lock index e97a38179..eefbb4239 100644 --- a/flake.lock +++ b/flake.lock @@ -18,16 +18,15 @@ }, "nixpkgs": { "locked": { - "lastModified": 1631098960, - "narHash": "sha256-6j6G/omHEFAnI2x7UvdrviGDNqiq1Fjd1A58Q6uc4sQ=", + "lastModified": 1633621759, + "narHash": "sha256-Mw29zuYjOozICTWsc9RvjuR7hW5D0H83onQh/WoVrMs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "12eb1d16ae3b6cbf0ea83e9228bca8ffd7cfe347", + "rev": "6755a884b24038a73dd4c8022dbb05375feef0a7", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-21.05", "repo": "nixpkgs", "type": "github" } @@ -38,18 +37,18 @@ "nixpkgs": "nixpkgs", "src-migen": "src-migen", "src-misoc": "src-misoc", - "src-pythonparser": "src-pythonparser", + "src-nac3": "src-nac3", "src-sipyco": "src-sipyco" } }, "src-migen": { "flake": false, "locked": { - "lastModified": 1628592379, - "narHash": "sha256-TQV6p0+Ri9HVge4qUKOCXe96cmcimNZ3R4sVwNY67DA=", + "lastModified": 1633615575, + "narHash": "sha256-frh+WVOkEKMpVEMhdE/GZKSj82XnSC8OF8SWNluk/Yg=", "owner": "m-labs", "repo": "migen", - "rev": "27dbf03edd75c32dc1706e2a1316950c3a8d452a", + "rev": "6e3f8e565704b4293174aedfb15b3470d233f528", "type": "github" }, "original": { @@ -76,30 +75,34 @@ "url": "https://github.com/m-labs/misoc.git" } }, - "src-pythonparser": { - "flake": false, + "src-nac3": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, "locked": { - "lastModified": 1628745371, - "narHash": "sha256-p6TgeeaK4NEmbhimEXp31W8hVRo4DgWmcCoqZ+UdN60=", - "owner": "m-labs", - "repo": "pythonparser", - "rev": "5413ee5c9f8760e95c6acd5d6e88dabb831ad201", - "type": "github" + "lastModified": 1633622662, + "narHash": "sha256-AEWqSxdl2aIibv7vtU9vDMu8ytdOY10fwBaM77+Il64=", + "ref": "master", + "rev": "79d3c5caae79fe15f41d2b2248cad2344389555f", + "revCount": 340, + "type": "git", + "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, "original": { - "owner": "m-labs", - "repo": "pythonparser", - "type": "github" + "type": "git", + "url": "https://git.m-labs.hk/M-Labs/nac3.git" } }, "src-sipyco": { "flake": false, "locked": { - "lastModified": 1623807309, - "narHash": "sha256-FTRAS4RjqDOygu6+cP8mKbZHu/YZ7YKpEe2gSzJc9rk=", + "lastModified": 1632832039, + "narHash": "sha256-GYXXCCOxNZyy6j7qScB3/QWUUCEVX+4tM4bXXVGXty0=", "owner": "m-labs", "repo": "sipyco", - "rev": "20c946aad78872fe60b78d9b57a624d69f3eea47", + "rev": "b83d8e5d82b25dba9393f0c12bdc5253f8138545", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index e4343766d..1abe0dc93 100644 --- a/flake.nix +++ b/flake.nix @@ -1,15 +1,15 @@ { description = "A leading-edge control system for quantum information experiments"; - inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-21.05; + inputs.nixpkgs.url = github:NixOS/nixpkgs; inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; }; inputs.src-sipyco = { url = github:m-labs/sipyco; flake = false; }; - inputs.src-pythonparser = { url = github:m-labs/pythonparser; flake = false; }; + inputs.src-nac3 = { type = "git"; url = "https://git.m-labs.hk/M-Labs/nac3.git"; inputs.nixpkgs.follows = "nixpkgs"; }; inputs.src-migen = { url = github:m-labs/migen; flake = false; }; inputs.src-misoc = { type = "git"; url = "https://github.com/m-labs/misoc.git"; submodules = true; flake = false; }; - outputs = { self, nixpkgs, mozilla-overlay, src-sipyco, src-pythonparser, src-migen, src-misoc }: + outputs = { self, nixpkgs, mozilla-overlay, src-sipyco, src-nac3, src-migen, src-misoc }: let pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; }; rustManifest = pkgs.fetchurl { @@ -50,13 +50,6 @@ propagatedBuildInputs = with pkgs.python3Packages; [ pybase64 numpy ]; }; - pythonparser = pkgs.python3Packages.buildPythonPackage { - name = "pythonparser"; - src = src-pythonparser; - doCheck = false; - propagatedBuildInputs = with pkgs.python3Packages; [ regex ]; - }; - qasync = pkgs.python3Packages.buildPythonPackage rec { pname = "qasync"; version = "0.10.0"; @@ -73,52 +66,6 @@ ''; }; - outputcheck = pkgs.python3Packages.buildPythonApplication rec { - pname = "outputcheck"; - version = "0.4.2"; - src = pkgs.fetchFromGitHub { - owner = "stp"; - repo = "OutputCheck"; - rev = "e0f533d3c5af2949349856c711bf4bca50022b48"; - sha256 = "1y27vz6jq6sywas07kz3v01sqjd0sga9yv9w2cksqac3v7wmf2a0"; - }; - prePatch = "echo ${version} > RELEASE-VERSION"; - }; - - libartiq-support = pkgs.stdenv.mkDerivation { - name = "libartiq-support"; - src = self; - buildInputs = [ rustPlatform.rust.rustc ]; - buildPhase = '' - rustc $src/artiq/test/libartiq_support/lib.rs -Cpanic=unwind -g - ''; - installPhase = '' - mkdir $out - cp libartiq_support.so $out - ''; - }; - - llvmlite-new = pkgs.python3Packages.buildPythonPackage rec { - pname = "llvmlite"; - version = "0.37.0rc2"; - src = pkgs.python3Packages.fetchPypi { - inherit pname version; - sha256 = "sha256-F1quz+76JOt1jaQPVzdKe7RfN6gWG2lyE82qTvgyY/c="; - }; - nativeBuildInputs = [ pkgs.llvm_11 ]; - # 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_11.dev}/bin/llvm-config - ''; - doCheck = false; # FIXME - }; - artiq = pkgs.python3Packages.buildPythonPackage rec { pname = "artiq"; version = "7.0-dev"; @@ -127,9 +74,9 @@ preBuild = "export VERSIONEER_OVERRIDE=${version}"; nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; - # keep llvm_x and lld_x in sync with llvmlite - propagatedBuildInputs = [ pkgs.llvm_11 pkgs.lld_11 llvmlite-new sipyco pythonparser ] - ++ (with pkgs.python3Packages; [ pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial python-Levenshtein h5py pyqt5 qasync ]); + # keep llvm_x and lld_x in sync with nac3 + propagatedBuildInputs = [ pkgs.llvm_11 pkgs.lld_11 src-nac3.packages.x86_64-linux.nac3artiq sipyco ] + ++ (with pkgs.python3Packages; [ pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial h5py pyqt5 qasync ]); dontWrapQtApps = true; postFixup = '' @@ -146,14 +93,11 @@ ]; # FIXME: automatically propagate lld_11 llvm_11 dependencies - checkInputs = [ pkgs.lld_11 pkgs.llvm_11 pkgs.lit outputcheck ]; + checkInputs = [ pkgs.lld_11 pkgs.llvm_11 ]; checkPhase = '' python -m unittest discover -v artiq.test - - TESTDIR=`mktemp -d` - cp --no-preserve=mode,ownership -R $src/artiq/test/lit $TESTDIR - LIBARTIQ_SUPPORT=${libartiq-support}/libartiq_support.so lit -v $TESTDIR/lit ''; + doCheck = false; # TODO }; migen = pkgs.python3Packages.buildPythonPackage rec { @@ -350,57 +294,6 @@ hydraJobs = { inherit (packages.x86_64-linux) artiq artiq-board-kc705-nist_clock openocd-bscanspi; - kc705-hitl = pkgs.stdenv.mkDerivation { - name = "kc705-hitl"; - - # requires patched Nix - __networked = true; - - buildInputs = [ - (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ artiq artiq-board-kc705-nist_clock ps.paramiko ])) - pkgs.llvm_11 - pkgs.lld_11 - pkgs.openssh - packages.x86_64-linux.openocd-bscanspi # for the bscanspi bitstreams - ]; - phases = [ "buildPhase" ]; - buildPhase = - '' - export HOME=`mktemp -d` - mkdir $HOME/.ssh - cp /opt/hydra_id_rsa $HOME/.ssh/id_rsa - cp /opt/hydra_id_rsa.pub $HOME/.ssh/id_rsa.pub - echo "rpi-1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPOBQVcsvk6WgRj18v4m0zkFeKrcN9gA+r6sxQxNwFpv" > $HOME/.ssh/known_hosts - chmod 600 $HOME/.ssh/id_rsa - LOCKCTL=$(mktemp -d) - mkfifo $LOCKCTL/lockctl - - cat $LOCKCTL/lockctl | ${pkgs.openssh}/bin/ssh \ - -i $HOME/.ssh/id_rsa \ - -o UserKnownHostsFile=$HOME/.ssh/known_hosts \ - rpi-1 \ - 'mkdir -p /tmp/board_lock && flock /tmp/board_lock/kc705-1 -c "echo Ok; cat"' \ - | ( - # End remote flock via FIFO - atexit_unlock() { - echo > $LOCKCTL/lockctl - } - trap atexit_unlock EXIT - - # Read "Ok" line when remote successfully locked - read LOCK_OK - - artiq_flash -t kc705 -H rpi-1 - sleep 15 - - export ARTIQ_ROOT=`python -c "import artiq; print(artiq.__path__[0])"`/examples/kc705_nist_clock - export ARTIQ_LOW_LATENCY=1 - python -m unittest discover -v artiq.test.coredevice - ) - - touch $out - ''; - }; }; }; diff --git a/setup.py b/setup.py index d888e9402..e5752f47c 100755 --- a/setup.py +++ b/setup.py @@ -6,8 +6,8 @@ import sys import versioneer -if sys.version_info[:2] < (3, 7): - raise Exception("You need Python 3.7+") +if sys.version_info[:2] < (3, 9): + raise Exception("You need Python 3.9+") # Depends on PyQt5, but setuptools cannot check for it. @@ -15,7 +15,9 @@ requirements = [ "numpy", "scipy", "python-dateutil", "prettytable", "h5py", "qasync", "pyqtgraph", "pygit2", - "llvmlite", "pythonparser", "python-Levenshtein", + # FIXME: figure out how to get the setuptools crap to find nac3artiq. Python imports it just fine. + # See: https://github.com/PyO3/setuptools-rust + # Alternatively, stop using setuptools, it sucks. ] console_scripts = [ @@ -58,7 +60,7 @@ Intended Audience :: Science/Research License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+) Operating System :: Microsoft :: Windows Operating System :: POSIX :: Linux -Programming Language :: Python :: 3.7 +Programming Language :: Python :: 3.9 Topic :: Scientific/Engineering :: Physics Topic :: System :: Hardware """.splitlines(), From 17c283d09189b284576d0bce52485db8954d8e6b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 10 Oct 2021 20:40:17 +0800 Subject: [PATCH 002/352] runtime: expose rint from libm --- artiq/firmware/ksupport/api.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 7b219562c..99add22fa 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -101,6 +101,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(log10), api!(nextafter), api!(pow), + api!(rint), api!(round), api!(sin), api!(sinh), From fbd5c70250555b0a251128d0f2326f5787ebfba7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Oct 2021 08:12:04 +0800 Subject: [PATCH 003/352] Revert "runtime: expose rint from libm" Consistency with NAR3/Zynq where rint is not available. This reverts commit f5100702f608cf34a24349510d29e7708c74a8d5. --- artiq/firmware/ksupport/api.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 99add22fa..7b219562c 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -101,7 +101,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(log10), api!(nextafter), api!(pow), - api!(rint), api!(round), api!(sin), api!(sinh), From 9a1a8e0e81c580dd2044831ad909aed4a0098b9f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 3 Nov 2021 21:39:44 +0800 Subject: [PATCH 004/352] update dependencies --- flake.lock | 28 ++++++++++++++-------------- flake.nix | 18 +++++++++--------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/flake.lock b/flake.lock index 8e3730ffd..3b7dc9ed8 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1629225446, - "narHash": "sha256-HJX4Pc5ZUAg4apxB/XHuJ+6ukzvRQqeZMjscOBst2bA=", + "lastModified": 1634833229, + "narHash": "sha256-uDbVCkW91/AY87mTwm8XrX2E133LTFqwYsYNNxBcY9M=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "0510159186dd2ef46e5464484fbdf119393afa58", + "rev": "6070a8ee799f629cb1d0004821f77ceed94d3992", "type": "github" }, "original": { @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1634758644, - "narHash": "sha256-H3UW/msC6wadg28lcgZv2Ge/P7dWxesL6i37a0GOeyM=", + "lastModified": 1635946136, + "narHash": "sha256-y1l0FK/nyRqb9CCImHNDJYYTtCnSNF2rK5RFc+qaMEg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "70904d4a9927a4d6e05c72c4aaac4370e05107f3", + "rev": "8429ae8722a319ebc26e9a38105e0797a824eb87", "type": "github" }, "original": { @@ -60,11 +60,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1634799783, - "narHash": "sha256-CbeXsLTwwYBWb5cfrVVYkcQYV207gi9+CQhzfeZbXGc=", + "lastModified": 1635235511, + "narHash": "sha256-XdBMBfup7JbUPzBi0An8GnQCIp7tiaczTrOwsPpvKCM=", "ref": "master", - "rev": "855914deace34880c69589022c52a8921f431063", - "revCount": 2375, + "rev": "34e545c190e08ada3f59712bdb71208ac6c39cbc", + "revCount": 2397, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" @@ -82,11 +82,11 @@ ] }, "locked": { - "lastModified": 1633622662, - "narHash": "sha256-AEWqSxdl2aIibv7vtU9vDMu8ytdOY10fwBaM77+Il64=", + "lastModified": 1635932388, + "narHash": "sha256-f8OEkvTqE3q+xgxjgO3Dnfi+neplozfJNrtBcPcMqg8=", "ref": "master", - "rev": "79d3c5caae79fe15f41d2b2248cad2344389555f", - "revCount": 340, + "rev": "36e4028f5bf4307b8deabcc3768af2708728cede", + "revCount": 387, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, diff --git a/flake.nix b/flake.nix index 41e07c0e5..27f40c42d 100644 --- a/flake.nix +++ b/flake.nix @@ -77,7 +77,7 @@ nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; # keep llvm_x and lld_x in sync with nac3 - propagatedBuildInputs = [ pkgs.llvm_11 pkgs.lld_11 src-nac3.packages.x86_64-linux.nac3artiq sipyco ] + propagatedBuildInputs = [ pkgs.llvm_12 pkgs.lld_12 src-nac3.packages.x86_64-linux.nac3artiq sipyco ] ++ (with pkgs.python3Packages; [ pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial h5py pyqt5 qasync ]); dontWrapQtApps = true; @@ -94,8 +94,8 @@ "--set FONTCONFIG_FILE ${pkgs.fontconfig.out}/etc/fonts/fonts.conf" ]; - # FIXME: automatically propagate lld_11 llvm_11 dependencies - checkInputs = [ pkgs.lld_11 pkgs.llvm_11 ]; + # FIXME: automatically propagate lld_12 llvm_12 dependencies + checkInputs = [ pkgs.lld_12 pkgs.llvm_12 ]; checkPhase = '' python -m unittest discover -v artiq.test ''; @@ -190,9 +190,9 @@ (pkgs.python3.withPackages(ps: [ migen misoc artiq ])) rustPlatform.rust.rustc rustPlatform.rust.cargo - pkgs.llvmPackages_11.clang-unwrapped - pkgs.llvm_11 - pkgs.lld_11 + pkgs.llvmPackages_12.clang-unwrapped + pkgs.llvm_12 + pkgs.lld_12 vivado rustPlatform.cargoSetupHook cargo-xbuild @@ -309,9 +309,9 @@ rustPlatform.rust.rustc rustPlatform.rust.cargo cargo-xbuild - pkgs.llvmPackages_11.clang-unwrapped - pkgs.llvm_11 - pkgs.lld_11 + pkgs.llvmPackages_12.clang-unwrapped + pkgs.llvm_12 + pkgs.lld_12 # use the vivado-env command to enter a FHS shell that lets you run the Vivado installer packages.x86_64-linux.vivadoEnv packages.x86_64-linux.vivado From a3543a5527a34a422fd5f7f0eed9026ae3f3532b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 3 Nov 2021 21:51:16 +0800 Subject: [PATCH 005/352] bump ARTIQ version number --- MAJOR_VERSION | 2 +- flake.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MAJOR_VERSION b/MAJOR_VERSION index 7f8f011eb..45a4fb75d 100644 --- a/MAJOR_VERSION +++ b/MAJOR_VERSION @@ -1 +1 @@ -7 +8 diff --git a/flake.nix b/flake.nix index 27f40c42d..ada7bab88 100644 --- a/flake.nix +++ b/flake.nix @@ -70,7 +70,7 @@ artiq = pkgs.python3Packages.buildPythonPackage rec { pname = "artiq"; - version = "7.0-dev"; + version = "8.0-dev"; src = self; preBuild = "export VERSIONEER_OVERRIDE=${version}"; From e5620a6b7f74a466aeceb95a8d9cde4a299f5abf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 3 Nov 2021 22:07:33 +0800 Subject: [PATCH 006/352] language: remove old type annotations --- artiq/language/__init__.py | 4 +--- artiq/language/types.py | 27 --------------------------- 2 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 artiq/language/types.py diff --git a/artiq/language/__init__.py b/artiq/language/__init__.py index e5433d3b0..fef1a93ca 100644 --- a/artiq/language/__init__.py +++ b/artiq/language/__init__.py @@ -1,13 +1,11 @@ -from artiq.language import core, types, environment, units, scan +from artiq.language import core, environment, units, scan from artiq.language.core import * -from artiq.language.types import * from artiq.language.environment import * from artiq.language.units import * from artiq.language.scan import * __all__ = [] __all__.extend(core.__all__) -__all__.extend(types.__all__) __all__.extend(environment.__all__) __all__.extend(units.__all__) __all__.extend(scan.__all__) diff --git a/artiq/language/types.py b/artiq/language/types.py deleted file mode 100644 index 4a186788a..000000000 --- a/artiq/language/types.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Values representing ARTIQ types, to be used in function type -annotations. -""" - -from artiq.compiler import types, builtins - -__all__ = ["TNone", "TTuple", - "TBool", "TInt32", "TInt64", "TFloat", - "TStr", "TBytes", "TByteArray", - "TList", "TArray", "TRange32", "TRange64", - "TVar"] - -TNone = builtins.TNone() -TBool = builtins.TBool() -TInt32 = builtins.TInt(types.TValue(32)) -TInt64 = builtins.TInt(types.TValue(64)) -TFloat = builtins.TFloat() -TStr = builtins.TStr() -TBytes = builtins.TBytes() -TByteArray = builtins.TByteArray() -TTuple = types.TTuple -TList = builtins.TList -TArray = builtins.TArray -TRange32 = builtins.TRange(builtins.TInt(types.TValue(32))) -TRange64 = builtins.TRange(builtins.TInt(types.TValue(64))) -TVar = types.TVar From 2f60a38a9c7d6df525fd649298aad4214cfada94 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Nov 2021 12:16:29 +0800 Subject: [PATCH 007/352] flake: update dependencies --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 3b7dc9ed8..36927591b 100644 --- a/flake.lock +++ b/flake.lock @@ -82,11 +82,11 @@ ] }, "locked": { - "lastModified": 1635932388, - "narHash": "sha256-f8OEkvTqE3q+xgxjgO3Dnfi+neplozfJNrtBcPcMqg8=", + "lastModified": 1636252154, + "narHash": "sha256-YPRjk9M9GdUiAZircxUl5BDU8rN5t0B0ZkIau+dMqmg=", "ref": "master", - "rev": "36e4028f5bf4307b8deabcc3768af2708728cede", - "revCount": 387, + "rev": "50f1aca1aa7ecb4412aa4b8a0daa1cc644d8ca89", + "revCount": 412, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From c8ebd80fe2241a7e153389add0cb91dd44380d2c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Nov 2021 12:18:20 +0800 Subject: [PATCH 008/352] NAC3 integration WIP --- artiq/coredevice/core.py | 130 +++++--------- artiq/frontend/artiq_compile.py | 27 +-- artiq/language/core.py | 296 +++++++------------------------- artiq/tools.py | 3 + 4 files changed, 111 insertions(+), 345 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 191a90de7..e10b0ccc4 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -1,55 +1,29 @@ import os, sys -import numpy +from numpy import int32, int64 -from artiq import __artiq_dir__ as artiq_dir +import nac3artiq from artiq.language.core import * -from artiq.language.types import * +from artiq.language import core as core_language from artiq.language.units import * -from artiq.compiler.module import Module -from artiq.compiler.embedding import Stitcher -from artiq.compiler.targets import RISCVTarget, CortexA9Target - from artiq.coredevice.comm_kernel import CommKernel, CommKernelDummy -# Import for side effects (creating the exception classes). -from artiq.coredevice import exceptions -def _render_diagnostic(diagnostic, colored): - def shorten_path(path): - return path.replace(artiq_dir, "") - lines = [shorten_path(path) for path in diagnostic.render(colored=colored)] - return "\n".join(lines) - -colors_supported = os.name == "posix" -class _DiagnosticEngine(diagnostic.Engine): - def render_diagnostic(self, diagnostic): - sys.stderr.write(_render_diagnostic(diagnostic, colored=colors_supported) + "\n") - -class CompileError(Exception): - def __init__(self, diagnostic): - self.diagnostic = diagnostic - - def __str__(self): - # Prepend a newline so that the message shows up on after - # exception class name printed by Python. - return "\n" + _render_diagnostic(self.diagnostic, colored=colors_supported) - - -@syscall -def rtio_init() -> TNone: +@extern +def rtio_init(): raise NotImplementedError("syscall not simulated") -@syscall(flags={"nounwind", "nowrite"}) -def rtio_get_destination_status(linkno: TInt32) -> TBool: +@extern +def rtio_get_destination_status(destination: int32) -> bool: raise NotImplementedError("syscall not simulated") -@syscall(flags={"nounwind", "nowrite"}) -def rtio_get_counter() -> TInt64: +@extern +def rtio_get_counter() -> int64: raise NotImplementedError("syscall not simulated") +@nac3 class Core: """Core device driver. @@ -64,89 +38,65 @@ class Core: and the RTIO coarse timestamp frequency (e.g. SERDES multiplication factor). """ - - kernel_invariants = { - "core", "ref_period", "coarse_ref_period", "ref_multiplier", - } + ref_period: KernelInvariant[float] + ref_multiplier: KernelInvariant[int32] + coarse_ref_period: KernelInvariant[float] def __init__(self, dmgr, host, ref_period, ref_multiplier=8, target="riscv"): self.ref_period = ref_period self.ref_multiplier = ref_multiplier - if target == "riscv": - self.target_cls = RISCVTarget - elif target == "cortexa9": - self.target_cls = CortexA9Target - else: - raise ValueError("Unsupported target") self.coarse_ref_period = ref_period*ref_multiplier if host is None: self.comm = CommKernelDummy() else: self.comm = CommKernel(host) - self.first_run = True self.dmgr = dmgr self.core = self self.comm.core = self + self.compiler = nac3artiq.NAC3(target) def close(self): self.comm.close() - def compile(self, function, args, kwargs, set_result=None, - attribute_writeback=True, print_as_rpc=True): - try: - engine = _DiagnosticEngine(all_errors_are_fatal=True) + def compile(self, method, args, kwargs, file_output=None): + if core_language._allow_module_registration: + self.compiler.analyze_modules(core_language._registered_modules) + core_language._allow_module_registration = False - stitcher = Stitcher(engine=engine, core=self, dmgr=self.dmgr, - print_as_rpc=print_as_rpc) - stitcher.stitch_call(function, args, kwargs, set_result) - stitcher.finalize() + if hasattr(method, "__self__"): + obj = method.__self__ + name = method.__name__ + else: + obj = method + name = "" - module = Module(stitcher, - ref_period=self.ref_period, - attribute_writeback=attribute_writeback) - target = self.target_cls() - - library = target.compile_and_link([module]) - stripped_library = target.strip(library) - - return stitcher.embedding_map, stripped_library, \ - lambda addresses: target.symbolize(library, addresses), \ - lambda symbols: target.demangle(symbols) - except diagnostic.Error as error: - raise CompileError(error.diagnostic) from error + if file_output is None: + return self.compiler.compile_method_to_mem(obj, name, args) + else: + self.compiler.compile_method_to_file(obj, name, args, file_output) def run(self, function, args, kwargs): - result = None - @rpc(flags={"async"}) - def set_result(new_result): - nonlocal result - result = new_result - - embedding_map, kernel_library, symbolizer, demangler = \ - self.compile(function, args, kwargs, set_result) - + kernel_library = self.compile(function, args, kwargs) if self.first_run: self.comm.check_system_info() self.first_run = False - self.comm.load(kernel_library) self.comm.run() - self.comm.serve(embedding_map, symbolizer, demangler) - + self.comm.serve(None, None, None) return result @portable - def seconds_to_mu(self, seconds): + def seconds_to_mu(self, seconds: float): """Convert seconds to the corresponding number of machine units (RTIO cycles). :param seconds: time (in seconds) to convert. """ - return numpy.int64(seconds//self.ref_period) + return int64(seconds//self.ref_period) @portable - def mu_to_seconds(self, mu): + def mu_to_seconds(self, mu: int64): """Convert machine units (RTIO cycles) to seconds. :param mu: cycle count to convert. @@ -154,7 +104,11 @@ class Core: return mu*self.ref_period @kernel - def get_rtio_counter_mu(self): + def delay(self, dt: float): + delay_mu(self.seconds_to_mu(dt)) + + @kernel + def get_rtio_counter_mu(self) -> int64: """Retrieve the current value of the hardware RTIO timeline counter. As the timing of kernel code executed on the CPU is inherently @@ -167,7 +121,7 @@ class Core: return rtio_get_counter() @kernel - def wait_until_mu(self, cursor_mu): + def wait_until_mu(self, cursor_mu: int64): """Block execution until the hardware RTIO counter reaches the given value (see :meth:`get_rtio_counter_mu`). @@ -178,7 +132,7 @@ class Core: pass @kernel - def get_rtio_destination_status(self, destination): + def get_rtio_destination_status(self, destination: int32): """Returns whether the specified RTIO destination is up. This is particularly useful in startup kernels to delay startup until certain DRTIO destinations are up.""" @@ -190,7 +144,7 @@ class Core: at the current value of the hardware RTIO counter plus a margin of 125000 machine units.""" rtio_init() - at_mu(rtio_get_counter() + 125000) + at_mu(rtio_get_counter() + int64(125000)) @kernel def break_realtime(self): @@ -199,6 +153,6 @@ class Core: If the time cursor is already after that position, this function does nothing.""" - min_now = rtio_get_counter() + 125000 + min_now = rtio_get_counter() + int64(125000) if now_mu() < min_now: at_mu(min_now) diff --git a/artiq/frontend/artiq_compile.py b/artiq/frontend/artiq_compile.py index 1609971e0..95be09c9c 100755 --- a/artiq/frontend/artiq_compile.py +++ b/artiq/frontend/artiq_compile.py @@ -8,7 +8,6 @@ from artiq import __version__ as artiq_version from artiq.master.databases import DeviceDB, DatasetDB from artiq.master.worker_db import DeviceManager, DatasetManager from artiq.language.environment import ProcessArgumentManager -from artiq.coredevice.core import CompileError from artiq.tools import * @@ -47,6 +46,11 @@ def main(): device_mgr = DeviceManager(DeviceDB(args.device_db)) dataset_mgr = DatasetManager(DatasetDB(args.dataset_db)) + output = args.output + if output is None: + basename, ext = os.path.splitext(args.file) + output = "{}.elf".format(basename) + try: module = file_import(args.file, prefix="artiq_run_") exp = get_experiment(module, args.class_name) @@ -54,29 +58,12 @@ def main(): argument_mgr = ProcessArgumentManager(arguments) exp_inst = exp((device_mgr, dataset_mgr, argument_mgr, {})) - if not hasattr(exp.run, "artiq_embedded"): + if not getattr(exp.run, "__artiq_kernel__", False): raise ValueError("Experiment entry point must be a kernel") - core_name = exp.run.artiq_embedded.core_name - core = getattr(exp_inst, core_name) - - object_map, kernel_library, _, _ = \ - core.compile(exp.run, [exp_inst], {}, - attribute_writeback=False, print_as_rpc=False) - except CompileError as error: - return + exp_inst.core.compile(exp_inst.run, [], {}, file_output=output) finally: device_mgr.close_devices() - if object_map.has_rpc(): - raise ValueError("Experiment must not use RPC") - - output = args.output - if output is None: - basename, ext = os.path.splitext(args.file) - output = "{}.elf".format(basename) - - with open(output, "wb") as f: - f.write(kernel_library) if __name__ == "__main__": main() diff --git a/artiq/language/core.py b/artiq/language/core.py index 5560398dd..4dfb22e9a 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -2,273 +2,95 @@ Core ARTIQ extensions to the Python language. """ -from collections import namedtuple +from typing import Generic, TypeVar from functools import wraps -import numpy +from inspect import getfullargspec, getmodule +from types import SimpleNamespace -__all__ = ["kernel", "portable", "rpc", "syscall", "host_only", - "kernel_from_string", "set_time_manager", "set_watchdog_factory", - "TerminationRequested"] - -# global namespace for kernels -kernel_globals = ( - "sequential", "parallel", "interleave", - "delay_mu", "now_mu", "at_mu", "delay", - "watchdog" -) -__all__.extend(kernel_globals) +__all__ = [ + "KernelInvariant", + "extern", "kernel", "portable", "nac3", "rpc", + "parallel", "sequential", + "set_watchdog_factory", "watchdog", "TerminationRequested" +] -_ARTIQEmbeddedInfo = namedtuple("_ARTIQEmbeddedInfo", - "core_name portable function syscall forbidden flags") +T = TypeVar('T') +class KernelInvariant(Generic[T]): + pass -def kernel(arg=None, flags={}): - """ - This decorator marks an object's method for execution on the core - device. - When a decorated method is called from the Python interpreter, the :attr:`core` - attribute of the object is retrieved and used as core device driver. The - core device driver will typically compile, transfer and run the method - (kernel) on the device. +_allow_module_registration = True +_registered_modules = set() - When kernels call another method: +def _register_module_of(obj): + assert _allow_module_registration + # Delay NAC3 analysis until all referenced variables are supposed to exist on the CPython side. + _registered_modules.add(getmodule(obj)) - - if the method is a kernel for the same core device, it is compiled - and sent in the same binary. Calls between kernels happen entirely on - the device. - - if the method is a regular Python method (not a kernel), it generates - a remote procedure call (RPC) for execution on the host. - The decorator takes an optional parameter that defaults to :attr`core` and - specifies the name of the attribute to use as core device driver. +def extern(function): + """Decorates a function declaration defined by the core device runtime.""" + _register_module_of(function) + return function - This decorator must be present in the global namespace of all modules using - it for the import cache to work properly. - """ - if isinstance(arg, str): - def inner_decorator(function): - @wraps(function) - def run_on_core(self, *k_args, **k_kwargs): - return getattr(self, arg).run(run_on_core, ((self,) + k_args), k_kwargs) - run_on_core.artiq_embedded = _ARTIQEmbeddedInfo( - core_name=arg, portable=False, function=function, syscall=None, - forbidden=False, flags=set(flags)) - return run_on_core - return inner_decorator - elif arg is None: - def inner_decorator(function): - return kernel(function, flags) - return inner_decorator + +def kernel(function_or_method): + """Decorates a function or method to be executed on the core device.""" + _register_module_of(function_or_method) + argspec = getfullargspec(function_or_method) + if argspec.args and argspec.args[0] == "self": + @wraps(function_or_method) + def run_on_core(self, *args, **kwargs): + fake_method = SimpleNamespace(__self__=self, __name__=function_or_method.__name__) + self.core.run(fake_method, *args, **kwargs) else: - return kernel("core", flags)(arg) + @wraps(function_or_method) + def run_on_core(*args, **kwargs): + raise RuntimeError("Kernel functions need explicit core.run()") + run_on_core.__artiq_kernel__ = True + return run_on_core -def portable(arg=None, flags={}): + +def portable(function): + """Decorates a function or method to be executed on the same device (host/core device) as the caller.""" + _register_module_of(function) + return function + + +def nac3(cls): """ - This decorator marks a function for execution on the same device as its - caller. - - In other words, a decorated function called from the interpreter on the - host will be executed on the host (no compilation and execution on the - core device). A decorated function called from a kernel will be executed - on the core device (no RPC). - - This decorator must be present in the global namespace of all modules using - it for the import cache to work properly. + Decorates a class to be analyzed by NAC3. + All classes containing kernels or portable methods must use this decorator. """ - if arg is None: - def inner_decorator(function): - return portable(function, flags) - return inner_decorator - else: - arg.artiq_embedded = \ - _ARTIQEmbeddedInfo(core_name=None, portable=True, function=arg, syscall=None, - forbidden=False, flags=set(flags)) - return arg + _register_module_of(cls) + return cls + def rpc(arg=None, flags={}): """ This decorator marks a function for execution on the host interpreter. - This is also the default behavior of ARTIQ; however, this decorator allows - specifying additional flags. """ if arg is None: def inner_decorator(function): return rpc(function, flags) return inner_decorator - else: - arg.artiq_embedded = \ - _ARTIQEmbeddedInfo(core_name=None, portable=False, function=arg, syscall=None, - forbidden=False, flags=set(flags)) - return arg - -def syscall(arg=None, flags={}): - """ - This decorator marks a function as a system call. When executed on a core - device, a C function with the provided name (or the same name as - the Python function, if not provided) will be called. When executed on - host, the Python function will be called as usual. - - Every argument and the return value must be annotated with ARTIQ types. - - Only drivers should normally define syscalls. - """ - if isinstance(arg, str): - def inner_decorator(function): - function.artiq_embedded = \ - _ARTIQEmbeddedInfo(core_name=None, portable=False, function=None, - syscall=arg, forbidden=False, - flags=set(flags)) - return function - return inner_decorator - elif arg is None: - def inner_decorator(function): - return syscall(function.__name__, flags)(function) - return inner_decorator - else: - return syscall(arg.__name__)(arg) - -def host_only(function): - """ - This decorator marks a function so that it can only be executed - in the host Python interpreter. - """ - function.artiq_embedded = \ - _ARTIQEmbeddedInfo(core_name=None, portable=False, function=None, syscall=None, - forbidden=True, flags={}) - return function -def kernel_from_string(parameters, body_code, decorator=kernel): - """Build a kernel function from the supplied source code in string form, - similar to ``exec()``/``eval()``. - - Operating on pieces of source code as strings is a very brittle form of - metaprogramming; kernels generated like this are hard to debug, and - inconvenient to write. Nevertheless, this can sometimes be useful to work - around restrictions in ARTIQ Python. In that instance, care should be taken - to keep string-generated code to a minimum and cleanly separate it from - surrounding code. - - The resulting function declaration is also evaluated using ``exec()`` for - use from host Python code. To encourage a modicum of code hygiene, no - global symbols are available by default; any objects accessed by the - function body must be passed in explicitly as parameters. - - :param parameters: A list of parameter names the generated functions - accepts. Each entry can either be a string or a tuple of two strings; - if the latter, the second element specifies the type annotation. - :param body_code: The code for the function body, in string form. - ``return`` statements can be used to return values, as usual. - :param decorator: One of ``kernel`` or ``portable`` (optionally with - parameters) to specify how the function will be executed. - - :return: The function generated from the arguments. - """ - - # Build complete function declaration. - decl = "def kernel_from_string_fn(" - for p in parameters: - type_annotation = "" - if isinstance(p, tuple): - name, typ = p - type_annotation = ": " + typ - else: - name = p - decl += name + type_annotation + "," - decl += "):\n" - decl += "\n".join(" " + line for line in body_code.split("\n")) - - # Evaluate to get host-side function declaration. - context = {} - try: - exec(decl, context) - except SyntaxError: - raise SyntaxError("Error parsing kernel function: '{}'".format(decl)) - fn = decorator(context["kernel_from_string_fn"]) - - # Save source code for the compiler to pick up later. - fn.artiq_embedded = fn.artiq_embedded._replace(function=decl) - return fn - - -class _DummyTimeManager: - def _not_implemented(self, *args, **kwargs): - raise NotImplementedError( - "Attempted to interpret kernel without a time manager") - - enter_sequential = _not_implemented - enter_parallel = _not_implemented - exit = _not_implemented - take_time_mu = _not_implemented - get_time_mu = _not_implemented - set_time_mu = _not_implemented - take_time = _not_implemented - -_time_manager = _DummyTimeManager() - - -def set_time_manager(time_manager): - """Set the time manager used for simulating kernels by running them - directly inside the Python interpreter. The time manager responds to the - entering and leaving of interleave/parallel/sequential blocks, delays, etc. and - provides a time-stamped logging facility for events. - """ - global _time_manager - _time_manager = time_manager - - -class _Sequential: - """In a sequential block, statements are executed one after another, with - the time increasing as one moves down the statement list.""" +@nac3 +class KernelContextManager: + @kernel def __enter__(self): - _time_manager.enter_sequential() + pass - def __exit__(self, type, value, traceback): - _time_manager.exit() -sequential = _Sequential() + @kernel + def __exit__(self): + pass +parallel = KernelContextManager() +sequential = KernelContextManager() -class _Parallel: - """In a parallel block, all top-level statements start their execution at - the same time. - - The execution time of a parallel block is the execution time of its longest - statement. A parallel block may contain sequential blocks, which themselves - may contain interleave blocks, etc. - """ - def __enter__(self): - _time_manager.enter_parallel() - - def __exit__(self, type, value, traceback): - _time_manager.exit() -parallel = _Parallel() -interleave = _Parallel() # no difference in semantics on host - -def delay_mu(duration): - """Increases the RTIO time by the given amount (in machine units).""" - _time_manager.take_time_mu(duration) - - -def now_mu(): - """Retrieve the current RTIO timeline cursor, in machine units. - - Note the conceptual difference between this and the current value of the - hardware RTIO counter; see e.g. - :meth:`artiq.coredevice.core.Core.get_rtio_counter_mu` for the latter. - """ - return _time_manager.get_time_mu() - - -def at_mu(time): - """Sets the RTIO time to the specified absolute value, in machine units.""" - _time_manager.set_time_mu(time) - - -def delay(duration): - """Increases the RTIO time by the given amount (in seconds).""" - _time_manager.take_time(duration) class _DummyWatchdog: diff --git a/artiq/tools.py b/artiq/tools.py index 167f8cf74..106fcf958 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -80,6 +80,9 @@ def file_import(filename, prefix="file_import_"): try: spec = importlib.util.spec_from_file_location(modname, filename) module = importlib.util.module_from_spec(spec) + # Add to sys.modules, otherwise inspect thinks it is a built-in module and often breaks. + # This must take place before module execution because NAC3 decorators call inspect. + sys.modules[modname] = module spec.loader.exec_module(module) finally: sys.path.remove(path) From 8f596ed04f566ca74ed57b75f01e6034e8e8c047 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Nov 2021 12:37:05 +0800 Subject: [PATCH 009/352] coredevice: fix typing problems --- artiq/coredevice/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index e10b0ccc4..766ff0cef 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -87,7 +87,7 @@ class Core: return result @portable - def seconds_to_mu(self, seconds: float): + def seconds_to_mu(self, seconds: float) -> int64: """Convert seconds to the corresponding number of machine units (RTIO cycles). @@ -96,12 +96,12 @@ class Core: return int64(seconds//self.ref_period) @portable - def mu_to_seconds(self, mu: int64): + def mu_to_seconds(self, mu: int64) -> float: """Convert machine units (RTIO cycles) to seconds. :param mu: cycle count to convert. """ - return mu*self.ref_period + return float(mu)*self.ref_period @kernel def delay(self, dt: float): @@ -132,7 +132,7 @@ class Core: pass @kernel - def get_rtio_destination_status(self, destination: int32): + def get_rtio_destination_status(self, destination: int32) -> bool: """Returns whether the specified RTIO destination is up. This is particularly useful in startup kernels to delay startup until certain DRTIO destinations are up.""" From deb8a77464f546b8fd9646d2e7e0d5400281ed1d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Nov 2021 13:57:03 +0800 Subject: [PATCH 010/352] coredevice/rtio: port to NAC3 --- artiq/coredevice/rtio.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/artiq/coredevice/rtio.py b/artiq/coredevice/rtio.py index 7b5ab38a2..216f94bd4 100644 --- a/artiq/coredevice/rtio.py +++ b/artiq/coredevice/rtio.py @@ -1,30 +1,32 @@ -from artiq.language.core import syscall -from artiq.language.types import TInt32, TInt64, TList, TNone, TTuple +from numpy import int32, int64 +from typing import Tuple + +from artiq.language.core import extern -@syscall(flags={"nowrite"}) -def rtio_output(target: TInt32, data: TInt32) -> TNone: +@extern +def rtio_output(target: int32, data: int32): raise NotImplementedError("syscall not simulated") -@syscall(flags={"nowrite"}) -def rtio_output_wide(target: TInt32, data: TList(TInt32)) -> TNone: +@extern +def rtio_output_wide(target: int32, data: list[int32]): raise NotImplementedError("syscall not simulated") -@syscall(flags={"nowrite"}) -def rtio_input_timestamp(timeout_mu: TInt64, channel: TInt32) -> TInt64: +@extern +def rtio_input_timestamp(timeout_mu: int64, channel: int32) -> int64: raise NotImplementedError("syscall not simulated") -@syscall(flags={"nowrite"}) -def rtio_input_data(channel: TInt32) -> TInt32: +@extern +def rtio_input_data(channel: int32) -> int32: raise NotImplementedError("syscall not simulated") -@syscall(flags={"nowrite"}) -def rtio_input_timestamped_data(timeout_mu: TInt64, - channel: TInt32) -> TTuple([TInt64, TInt32]): +# NAC3TODO @extern +def rtio_input_timestamped_data(timeout_mu: int64, + channel: int32) -> Tuple[int64, int32]: """Wait for an input event up to timeout_mu on the given channel, and return a tuple of timestamp and attached data, or (-1, 0) if the timeout is reached.""" From 2f031285a40a41bb4ba1786000c2af494f35c4d9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Nov 2021 13:58:17 +0800 Subject: [PATCH 011/352] coredevice/ttl: port to NAC3 --- artiq/coredevice/ttl.py | 104 +++++++++++++++++++++++----------------- artiq/language/core.py | 6 ++- 2 files changed, 64 insertions(+), 46 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 2bc40ed58..0aec996da 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -6,10 +6,10 @@ replacement. For example, pulses of "zero" length (e.g. :meth:`TTLInOut.on` immediately followed by :meth:`TTLInOut.off`, without a delay) are suppressed. """ -import numpy +from numpy import int32, int64 from artiq.language.core import * -from artiq.language.types import * +from artiq.coredevice.core import Core from artiq.coredevice.rtio import (rtio_output, rtio_input_timestamp, rtio_input_data) from artiq.coredevice.exceptions import RTIOOverflow @@ -22,6 +22,7 @@ from artiq.coredevice.exceptions import RTIOOverflow # 3 Set input sensitivity and sample +@nac3 class TTLOut: """RTIO TTL output driver. @@ -29,7 +30,9 @@ class TTLOut: :param channel: channel number """ - kernel_invariants = {"core", "channel", "target_o"} + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + target_o: KernelInvariant[int32] def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) @@ -41,7 +44,7 @@ class TTLOut: pass @kernel - def set_o(self, o): + def set_o(self, o: bool): rtio_output(self.target_o, 1 if o else 0) @kernel @@ -61,7 +64,7 @@ class TTLOut: self.set_o(False) @kernel - def pulse_mu(self, duration): + def pulse_mu(self, duration: int64): """Pulse the output high for the specified duration (in machine units). @@ -71,16 +74,17 @@ class TTLOut: self.off() @kernel - def pulse(self, duration): + def pulse(self, duration: float): """Pulse the output high for the specified duration (in seconds). The time cursor is advanced by the specified duration.""" self.on() - delay(duration) + self.core.delay(duration) self.off() +@nac3 class TTLInOut: """RTIO TTL input/output driver. @@ -107,8 +111,13 @@ class TTLInOut: :param channel: channel number """ - kernel_invariants = {"core", "channel", "gate_latency_mu", - "target_o", "target_oe", "target_sens", "target_sample"} + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + gate_latency_mu: KernelInvariant[int32] + target_o: KernelInvariant[int32] + target_oe: KernelInvariant[int32] + target_sens: KernelInvariant[int32] + target_sample: KernelInvariant[int32] def __init__(self, dmgr, channel, gate_latency_mu=None, core_device="core"): @@ -129,7 +138,7 @@ class TTLInOut: self.target_sample = (channel << 8) + 3 @kernel - def set_oe(self, oe): + def set_oe(self, oe: bool): rtio_output(self.target_oe, 1 if oe else 0) @kernel @@ -159,7 +168,7 @@ class TTLInOut: self.set_oe(False) @kernel - def set_o(self, o): + def set_o(self, o: bool): rtio_output(self.target_o, 1 if o else 0) @kernel @@ -183,7 +192,7 @@ class TTLInOut: self.set_o(False) @kernel - def pulse_mu(self, duration): + def pulse_mu(self, duration: int64): """Pulse the output high for the specified duration (in machine units). @@ -193,22 +202,22 @@ class TTLInOut: self.off() @kernel - def pulse(self, duration): + def pulse(self, duration: float): """Pulse the output high for the specified duration (in seconds). The time cursor is advanced by the specified duration.""" self.on() - delay(duration) + self.core.delay(duration) self.off() # Input API: gating @kernel - def _set_sensitivity(self, value): + def _set_sensitivity(self, value: int32): rtio_output(self.target_sens, value) @kernel - def gate_rising_mu(self, duration): + def gate_rising_mu(self, duration: int64) -> int64: """Register rising edge events for the specified duration (in machine units). @@ -223,7 +232,7 @@ class TTLInOut: return now_mu() @kernel - def gate_falling_mu(self, duration): + def gate_falling_mu(self, duration: int64) -> int64: """Register falling edge events for the specified duration (in machine units). @@ -238,7 +247,7 @@ class TTLInOut: return now_mu() @kernel - def gate_both_mu(self, duration): + def gate_both_mu(self, duration: int64) -> int64: """Register both rising and falling edge events for the specified duration (in machine units). @@ -253,7 +262,7 @@ class TTLInOut: return now_mu() @kernel - def gate_rising(self, duration): + def gate_rising(self, duration: float) -> int64: """Register rising edge events for the specified duration (in seconds). @@ -263,12 +272,12 @@ class TTLInOut: convenience when used with :meth:`count`/:meth:`timestamp_mu`. """ self._set_sensitivity(1) - delay(duration) + self.core.delay(duration) self._set_sensitivity(0) return now_mu() @kernel - def gate_falling(self, duration): + def gate_falling(self, duration: float) -> int64: """Register falling edge events for the specified duration (in seconds). @@ -279,12 +288,12 @@ class TTLInOut: """ self._set_sensitivity(2) - delay(duration) + self.core.delay(duration) self._set_sensitivity(0) return now_mu() @kernel - def gate_both(self, duration): + def gate_both(self, duration: float) -> int64: """Register both rising and falling edge events for the specified duration (in seconds). @@ -294,12 +303,12 @@ class TTLInOut: convenience when used with :meth:`count`/:meth:`timestamp_mu`. """ self._set_sensitivity(3) - delay(duration) + self.core.delay(duration) self._set_sensitivity(0) return now_mu() - @kernel - def count(self, up_to_timestamp_mu): + # NAC3TODO @kernel + def count(self, up_to_timestamp_mu: int64) -> int32: """Consume RTIO input events until the hardware timestamp counter has reached the specified timestamp and return the number of observed events. @@ -347,12 +356,12 @@ class TTLInOut: ttl_input.count(ttl_input.gate_rising(100 * us)) """ count = 0 - while rtio_input_timestamp(up_to_timestamp_mu + self.gate_latency_mu, self.channel) >= 0: + while rtio_input_timestamp(up_to_timestamp_mu + int64(self.gate_latency_mu), self.channel) >= int64(0): count += 1 return count @kernel - def timestamp_mu(self, up_to_timestamp_mu): + def timestamp_mu(self, up_to_timestamp_mu: int64) -> int64: """Return the timestamp of the next RTIO input event, or -1 if the hardware timestamp counter reaches the given value before an event is received. @@ -370,7 +379,7 @@ class TTLInOut: :return: The timestamp (in machine units) of the first event received; -1 on timeout. """ - return rtio_input_timestamp(up_to_timestamp_mu + self.gate_latency_mu, self.channel) + return rtio_input_timestamp(up_to_timestamp_mu + int64(self.gate_latency_mu), self.channel) # Input API: sampling @kernel @@ -382,7 +391,7 @@ class TTLInOut: rtio_output(self.target_sample, 0) @kernel - def sample_get(self): + def sample_get(self) -> int32: """Returns the value of a sample previously obtained with :meth:`sample_input`. @@ -394,7 +403,7 @@ class TTLInOut: return rtio_input_data(self.channel) @kernel - def sample_get_nonrt(self): + def sample_get_nonrt(self) -> int32: """Convenience function that obtains the value of a sample at the position of the time cursor, breaks realtime, and returns the sample value.""" @@ -405,7 +414,7 @@ class TTLInOut: # Input API: watching @kernel - def watch_stay_on(self): + def watch_stay_on(self) -> bool: """Checks that the input is at a high level at the position of the time cursor and keep checking until :meth:`watch_done` is called. @@ -420,13 +429,13 @@ class TTLInOut: return rtio_input_data(self.channel) == 1 @kernel - def watch_stay_off(self): + def watch_stay_off(self) -> bool: """Like :meth:`watch_stay_on`, but for low levels.""" rtio_output(self.target_sample, 1) # gate rising return rtio_input_data(self.channel) == 0 - @kernel - def watch_done(self): + # NAC3TODO @kernel + def watch_done(self) -> bool: """Stop watching the input at the position of the time cursor. Returns ``True`` if the input has not changed state while it @@ -438,13 +447,14 @@ class TTLInOut: rtio_output(self.target_sens, 0) success = True try: - while rtio_input_timestamp(now_mu() + self.gate_latency_mu, self.channel) != -1: + while rtio_input_timestamp(now_mu() + int64(self.gate_latency_mu), self.channel) != -1: success = False except RTIOOverflow: success = False return success +@nac3 class TTLClockGen: """RTIO TTL clock generator driver. @@ -456,31 +466,35 @@ class TTLClockGen: :param channel: channel number :param acc_width: accumulator width in bits """ - kernel_invariants = {"core", "channel", "target", "acc_width"} + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + target: KernelInvariant[int32] + acc_width: KernelInvariant[int32] def __init__(self, dmgr, channel, acc_width=24, core_device="core"): self.core = dmgr.get(core_device) self.channel = channel self.target = channel << 8 - - self.acc_width = numpy.int64(acc_width) + self.acc_width = acc_width @portable - def frequency_to_ftw(self, frequency): + def frequency_to_ftw(self, frequency: float) -> int32: """Returns the frequency tuning word corresponding to the given frequency. """ - return round(2**self.acc_width*frequency*self.core.coarse_ref_period) + # NAC3TODO return round64(2**self.acc_width*frequency*self.core.coarse_ref_period) + return 0 @portable - def ftw_to_frequency(self, ftw): + def ftw_to_frequency(self, ftw: int32) -> float: """Returns the frequency corresponding to the given frequency tuning word. """ - return ftw/self.core.coarse_ref_period/2**self.acc_width + # NAC3TODO return float(ftw)/self.core.coarse_ref_period/2**int64(self.acc_width) + return 0.0 @kernel - def set_mu(self, frequency): + def set_mu(self, frequency: int32): """Set the frequency of the clock, in machine units, at the current position of the time cursor. @@ -500,7 +514,7 @@ class TTLClockGen: rtio_output(self.target, frequency) @kernel - def set(self, frequency): + def set(self, frequency: float): """Like :meth:`set_mu`, but using Hz.""" self.set_mu(self.frequency_to_ftw(frequency)) diff --git a/artiq/language/core.py b/artiq/language/core.py index 4dfb22e9a..36d8b459e 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -9,7 +9,7 @@ from types import SimpleNamespace __all__ = [ - "KernelInvariant", + "KernelInvariant", "round64", "extern", "kernel", "portable", "nac3", "rpc", "parallel", "sequential", "set_watchdog_factory", "watchdog", "TerminationRequested" @@ -21,6 +21,10 @@ class KernelInvariant(Generic[T]): pass +def round64(x): + return round(x) + + _allow_module_registration = True _registered_modules = set() From 262cd62544058d8bdd442c748119d7fab084332a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Nov 2021 13:59:59 +0800 Subject: [PATCH 012/352] examples/blink_forever: port to NAC3 --- .../kc705_nist_clock/repository/blink_forever.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/artiq/examples/kc705_nist_clock/repository/blink_forever.py b/artiq/examples/kc705_nist_clock/repository/blink_forever.py index 83c589ebe..68d5e031e 100644 --- a/artiq/examples/kc705_nist_clock/repository/blink_forever.py +++ b/artiq/examples/kc705_nist_clock/repository/blink_forever.py @@ -1,7 +1,12 @@ from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut - +@nac3 class BlinkForever(EnvExperiment): + core: KernelInvariant[Core] + led: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("led") @@ -10,5 +15,5 @@ class BlinkForever(EnvExperiment): def run(self): self.core.reset() while True: - self.led.pulse(100*ms) - delay(100*ms) + self.led.pulse(100.*ms) + self.core.delay(100.*ms) From b7313ddc32a500ab2132ec3e7d381393f04af18a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Nov 2021 15:32:07 +0800 Subject: [PATCH 013/352] coredevice/rtio: fix tuple annotation --- artiq/coredevice/rtio.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/rtio.py b/artiq/coredevice/rtio.py index 216f94bd4..befab9339 100644 --- a/artiq/coredevice/rtio.py +++ b/artiq/coredevice/rtio.py @@ -1,5 +1,4 @@ from numpy import int32, int64 -from typing import Tuple from artiq.language.core import extern @@ -24,9 +23,9 @@ def rtio_input_data(channel: int32) -> int32: raise NotImplementedError("syscall not simulated") -# NAC3TODO @extern +@extern def rtio_input_timestamped_data(timeout_mu: int64, - channel: int32) -> Tuple[int64, int32]: + channel: int32) -> tuple[int64, int32]: """Wait for an input event up to timeout_mu on the given channel, and return a tuple of timestamp and attached data, or (-1, 0) if the timeout is reached.""" From 31955d0c7a97069030360cfecc44bd0caee7e309 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Nov 2021 17:23:44 +0800 Subject: [PATCH 014/352] coredevice/spi2: port to NAC3 --- artiq/coredevice/spi2.py | 62 +++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index aa1045973..ae1bd2ef4 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -7,8 +7,10 @@ Output event replacement is not supported and issuing commands at the same time is an error. """ -from artiq.language.core import syscall, kernel, portable, delay_mu -from artiq.language.types import TInt32, TNone +from numpy import int32, int64 + +from artiq.language.core import nac3, KernelInvariant, kernel, portable, extern +from artiq.coredevice.core import Core from artiq.coredevice.rtio import rtio_output, rtio_input_data @@ -33,6 +35,7 @@ SPI_LSB_FIRST = 0x40 SPI_HALF_DUPLEX = 0x80 +@nac3 class SPIMaster: """Core device Serial Peripheral Interface (SPI) bus master. @@ -62,23 +65,25 @@ class SPIMaster: :meth:`update_xfer_duration_mu` :param core_device: Core device name """ - kernel_invariants = {"core", "ref_period_mu", "channel"} + core: KernelInvariant[Core] + ref_period_mu: KernelInvariant[int64] + channel: KernelInvariant[int32] + xfer_duration_mu: int64 def __init__(self, dmgr, channel, div=0, length=0, core_device="core"): self.core = dmgr.get(core_device) - self.ref_period_mu = self.core.seconds_to_mu( - self.core.coarse_ref_period) + self.ref_period_mu = self.core.seconds_to_mu(self.core.coarse_ref_period) assert self.ref_period_mu == self.core.ref_multiplier self.channel = channel self.update_xfer_duration_mu(div, length) @portable - def frequency_to_div(self, f): + def frequency_to_div(self, f: float) -> int32: """Convert a SPI clock frequency to the closest SPI clock divider.""" - return int(round(1/(f*self.core.mu_to_seconds(self.ref_period_mu)))) + return round(1./(f*self.core.mu_to_seconds(self.ref_period_mu))) @kernel - def set_config(self, flags, length, freq, cs): + def set_config(self, flags: int32, length: int32, freq: float, cs: int32): """Set the configuration register. * If ``SPI_CS_POLARITY`` is cleared (``cs`` active low, the default), @@ -145,7 +150,7 @@ class SPIMaster: self.set_config_mu(flags, length, self.frequency_to_div(freq), cs) @kernel - def set_config_mu(self, flags, length, div, cs): + def set_config_mu(self, flags: int32, length: int32, div: int32, cs: int32): """Set the ``config`` register (in SPI bus machine units). .. seealso:: :meth:`set_config` @@ -162,17 +167,18 @@ class SPIMaster: Or number of the chip select to assert if ``cs`` is decoded downstream. (reset=0) """ - if length > 32 or length < 1: - raise ValueError("Invalid SPI transfer length") - if div > 257 or div < 2: - raise ValueError("Invalid SPI clock divider") + # NAC3TODO + #if length > 32 or length < 1: + # raise ValueError("Invalid SPI transfer length") + #if div > 257 or div < 2: + # raise ValueError("Invalid SPI clock divider") rtio_output((self.channel << 8) | SPI_CONFIG_ADDR, flags | ((length - 1) << 8) | ((div - 2) << 16) | (cs << 24)) self.update_xfer_duration_mu(div, length) delay_mu(self.ref_period_mu) @portable - def update_xfer_duration_mu(self, div, length): + def update_xfer_duration_mu(self, div: int32, length: int32): """Calculate and set the transfer duration. This method updates the SPI transfer duration which is used @@ -195,10 +201,10 @@ class SPIMaster: :param div: SPI clock divider (see: :meth:`set_config_mu`) :param length: SPI transfer length (see: :meth:`set_config_mu`) """ - self.xfer_duration_mu = ((length + 1)*div + 1)*self.ref_period_mu + self.xfer_duration_mu = int64((length + 1)*div + 1)*self.ref_period_mu @kernel - def write(self, data): + def write(self, data: int32): """Write SPI data to shift register register and start transfer. * The ``data`` register and the shift register are 32 bits wide. @@ -226,7 +232,7 @@ class SPIMaster: delay_mu(self.xfer_duration_mu) @kernel - def read(self): + def read(self) -> int32: """Read SPI data submitted by the SPI core. For bit alignment and bit ordering see :meth:`set_config`. @@ -238,21 +244,22 @@ class SPIMaster: return rtio_input_data(self.channel) -@syscall(flags={"nounwind", "nowrite"}) -def spi_set_config(busno: TInt32, flags: TInt32, length: TInt32, div: TInt32, cs: TInt32) -> TNone: +@extern +def spi_set_config(busno: int32, flags: int32, length: int32, div: int32, cs: int32): raise NotImplementedError("syscall not simulated") -@syscall(flags={"nounwind", "nowrite"}) -def spi_write(busno: TInt32, data: TInt32) -> TNone: +@extern +def spi_write(busno: int32, data: int32): raise NotImplementedError("syscall not simulated") -@syscall(flags={"nounwind", "nowrite"}) -def spi_read(busno: TInt32) -> TInt32: +@extern +def spi_read(busno: int32) -> int32: raise NotImplementedError("syscall not simulated") +@nac3 class NRTSPIMaster: """Core device non-realtime Serial Peripheral Interface (SPI) bus master. Owns one non-realtime SPI bus. @@ -265,12 +272,15 @@ class NRTSPIMaster: See :class:`SPIMaster` for a description of the methods. """ + core: KernelInvariant[Core] + busno: KernelInvariant[int32] + def __init__(self, dmgr, busno=0, core_device="core"): self.core = dmgr.get(core_device) self.busno = busno @kernel - def set_config_mu(self, flags=0, length=8, div=6, cs=1): + def set_config_mu(self, flags: int32 = 0, length: int32 = 8, div: int32 = 6, cs: int32 = 1): """Set the ``config`` register. Note that the non-realtime SPI cores are usually clocked by the system @@ -280,9 +290,9 @@ class NRTSPIMaster: spi_set_config(self.busno, flags, length, div, cs) @kernel - def write(self, data=0): + def write(self, data: int32 = 0): spi_write(self.busno, data) @kernel - def read(self): + def read(self) -> int32: return spi_read(self.busno) From 93f24c9f9477775eb73715f6639a7a6f27ecf272 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Nov 2021 19:01:44 +0800 Subject: [PATCH 015/352] coredevice/urukul: port to NAC3 --- artiq/coredevice/urukul.py | 151 +++++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 65 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 7cda7a4ce..f329f0df7 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -1,15 +1,17 @@ from numpy import int32, int64 -from artiq.language.core import kernel, delay, portable, at_mu, now_mu +from artiq.language.core import nac3, KernelInvariant, kernel, portable from artiq.language.units import us, ms -from artiq.language.types import TInt32, TFloat, TBool -from artiq.coredevice import spi2 as spi +from artiq.coredevice.core import Core +from artiq.coredevice.spi2 import * +from artiq.coredevice.ttl import TTLOut -SPI_CONFIG = (0 * spi.SPI_OFFLINE | 0 * spi.SPI_END | - 0 * spi.SPI_INPUT | 1 * spi.SPI_CS_POLARITY | - 0 * spi.SPI_CLK_POLARITY | 0 * spi.SPI_CLK_PHASE | - 0 * spi.SPI_LSB_FIRST | 0 * spi.SPI_HALF_DUPLEX) + +SPI_CONFIG = (0 * SPI_OFFLINE | 0 * SPI_END | + 0 * SPI_INPUT | 1 * SPI_CS_POLARITY | + 0 * SPI_CLK_POLARITY | 0 * SPI_CLK_PHASE | + 0 * SPI_LSB_FIRST | 0 * SPI_HALF_DUPLEX) # SPI clock write and read dividers SPIT_CFG_WR = 2 @@ -54,8 +56,8 @@ CS_DDS_CH3 = 7 @portable -def urukul_cfg(rf_sw, led, profile, io_update, mask_nu, - clk_sel, sync_sel, rst, io_rst, clk_div): +def urukul_cfg(rf_sw: int32, led: int32, profile: int32, io_update: int32, mask_nu: int32, + clk_sel: int32, sync_sel: int32, rst: int32, io_rst: int32, clk_div: int32) -> int32: """Build Urukul CPLD configuration register""" return ((rf_sw << CFG_RF_SW) | (led << CFG_LED) | @@ -71,56 +73,45 @@ def urukul_cfg(rf_sw, led, profile, io_update, mask_nu, @portable -def urukul_sta_rf_sw(sta): +def urukul_sta_rf_sw(sta: int32) -> int32: """Return the RF switch status from Urukul status register value.""" return (sta >> STA_RF_SW) & 0xf @portable -def urukul_sta_smp_err(sta): +def urukul_sta_smp_err(sta: int32) -> int32: """Return the SMP_ERR status from Urukul status register value.""" return (sta >> STA_SMP_ERR) & 0xf @portable -def urukul_sta_pll_lock(sta): +def urukul_sta_pll_lock(sta: int32) -> int32: """Return the PLL_LOCK status from Urukul status register value.""" return (sta >> STA_PLL_LOCK) & 0xf @portable -def urukul_sta_ifc_mode(sta): +def urukul_sta_ifc_mode(sta: int32) -> int32: """Return the IFC_MODE status from Urukul status register value.""" return (sta >> STA_IFC_MODE) & 0xf @portable -def urukul_sta_proto_rev(sta): +def urukul_sta_proto_rev(sta: int32) -> int32: """Return the PROTO_REV value from Urukul status register value.""" return (sta >> STA_PROTO_REV) & 0x7f - -class _RegIOUpdate: - def __init__(self, cpld): - self.cpld = cpld - - @kernel - def pulse(self, t: TFloat): - cfg = self.cpld.cfg_reg - self.cpld.cfg_write(cfg | (1 << CFG_IO_UPDATE)) - delay(t) - self.cpld.cfg_write(cfg) - - +@nac3 class _DummySync: def __init__(self, cpld): self.cpld = cpld @kernel - def set_mu(self, ftw: TInt32): + def set_mu(self, ftw: int32): pass +@nac3 class CPLD: """Urukul CPLD SPI router and configuration interface. @@ -159,7 +150,16 @@ class CPLD: front panel SMA with no clock connected), then the ``init()`` method of the DDS channels can fail with the error message ``PLL lock timeout``. """ - kernel_invariants = {"refclk", "bus", "core", "io_update", "clk_div"} + + core: KernelInvariant[Core] + refclk: KernelInvariant[float] + bus: KernelInvariant[SPIMaster] + io_update: KernelInvariant[TTLOut] + clk_div: KernelInvariant[int32] + sync: KernelInvariant[_DummySync] + cfg_reg: int32 + att_reg: int32 + sync_div: int32 def __init__(self, dmgr, spi_device, io_update_device=None, dds_reset_device=None, sync_device=None, @@ -176,13 +176,17 @@ class CPLD: if io_update_device is not None: self.io_update = dmgr.get(io_update_device) else: - self.io_update = _RegIOUpdate(self) + self.io_update = _RegIOUpdate(self.core, self) + # NAC3TODO + raise NotImplementedError if dds_reset_device is not None: self.dds_reset = dmgr.get(dds_reset_device) if sync_device is not None: self.sync = dmgr.get(sync_device) if sync_div is None: sync_div = 2 + # NAC3TODO + raise NotImplementedError else: self.sync = _DummySync(self) assert sync_div is None @@ -196,7 +200,7 @@ class CPLD: self.sync_div = sync_div @kernel - def cfg_write(self, cfg: TInt32): + def cfg_write(self, cfg: int32): """Write to the configuration register. See :func:`urukul_cfg` for possible flags. @@ -204,13 +208,13 @@ class CPLD: :param cfg: 24 bit data to be written. Will be stored at :attr:`cfg_reg`. """ - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24, + self.bus.set_config_mu(SPI_CONFIG | SPI_END, 24, SPIT_CFG_WR, CS_CFG) self.bus.write(cfg << 8) self.cfg_reg = cfg @kernel - def sta_read(self) -> TInt32: + def sta_read(self) -> int32: """Read the status register. Use any of the following functions to extract values: @@ -223,13 +227,13 @@ class CPLD: :return: The status register value. """ - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 24, + self.bus.set_config_mu(SPI_CONFIG | SPI_END | SPI_INPUT, 24, SPIT_CFG_RD, CS_CFG) self.bus.write(self.cfg_reg << 8) return self.bus.read() @kernel - def init(self, blind: TBool = False): + def init(self, blind: bool = False): """Initialize and detect Urukul. Resets the DDS I/O interface and verifies correct CPLD gateware @@ -246,13 +250,14 @@ class CPLD: else: proto_rev = urukul_sta_proto_rev(self.sta_read()) if proto_rev != STA_PROTO_REV_MATCH: - raise ValueError("Urukul proto_rev mismatch") - delay(100 * us) # reset, slack + # NAC3TODO raise ValueError("Urukul proto_rev mismatch") + pass + self.core.delay(100. * us) # reset, slack self.cfg_write(cfg) - if self.sync_div: - at_mu(now_mu() & ~0xf) # align to RTIO/2 + if self.sync_div != 0: + at_mu(now_mu() & ~int64(0xf)) # align to RTIO/2 self.set_sync_div(self.sync_div) # 125 MHz/2 = 1 GHz/16 - delay(1 * ms) # DDS wake up + self.core.delay(1. * ms) # DDS wake up @kernel def io_rst(self): @@ -260,8 +265,8 @@ class CPLD: self.cfg_write(self.cfg_reg | (1 << CFG_IO_RST)) self.cfg_write(self.cfg_reg & ~(1 << CFG_IO_RST)) - @kernel - def cfg_sw(self, channel: TInt32, on: TBool): + # NAC3TODO @kernel + def cfg_sw(self, channel: int32, on: bool): """Configure the RF switches through the configuration register. These values are logically OR-ed with the LVDS lines on EEM1. @@ -277,15 +282,15 @@ class CPLD: self.cfg_write(c) @kernel - def cfg_switches(self, state: TInt32): + def cfg_switches(self, state: int32): """Configure all four RF switches through the configuration register. :param state: RF switch state as a 4 bit integer. """ self.cfg_write((self.cfg_reg & ~0xf) | state) - @portable(flags={"fast-math"}) - def mu_to_att(self, att_mu: TInt32) -> TFloat: + @portable + def mu_to_att(self, att_mu: int32) -> float: """Convert a digital attenuation setting to dB. :param att_mu: Digital attenuation setting. @@ -293,20 +298,21 @@ class CPLD: """ return (255 - (att_mu & 0xff)) / 8 - @portable(flags={"fast-math"}) - def att_to_mu(self, att: TFloat) -> TInt32: + @portable + def att_to_mu(self, att: float) -> int32: """Convert an attenuation setting in dB to machine units. :param att: Attenuation setting in dB. :return: Digital attenuation setting. """ - code = int32(255) - int32(round(att * 8)) + code = 255 - round(att * 8.) if code < 0 or code > 255: - raise ValueError("Invalid urukul.CPLD attenuation!") + # NAC3TODO raise ValueError("Invalid urukul.CPLD attenuation!") + pass return code - @kernel - def set_att_mu(self, channel: TInt32, att: TInt32): + # NAC3TODO @kernel + def set_att_mu(self, channel: int32, att: int32): """Set digital step attenuator in machine units. This method will also write the attenuator settings of the three @@ -322,20 +328,20 @@ class CPLD: self.set_all_att_mu(a) @kernel - def set_all_att_mu(self, att_reg: TInt32): + def set_all_att_mu(self, att_reg: int32): """Set all four digital step attenuators (in machine units). .. seealso:: :meth:`set_att_mu` :param att_reg: Attenuator setting string (32 bit) """ - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32, + self.bus.set_config_mu(SPI_CONFIG | SPI_END, 32, SPIT_ATT_WR, CS_ATT) self.bus.write(att_reg) self.att_reg = att_reg - @kernel - def set_att(self, channel: TInt32, att: TFloat): + # NAC3TODO @kernel + def set_att(self, channel: int32, att: float): """Set digital step attenuator in SI units. This method will write the attenuator settings of all four channels. @@ -350,7 +356,7 @@ class CPLD: self.set_att_mu(channel, self.att_to_mu(att)) @kernel - def get_att_mu(self) -> TInt32: + def get_att_mu(self) -> int32: """Return the digital step attenuator settings in machine units. The result is stored and will be used in future calls of @@ -360,18 +366,18 @@ class CPLD: :return: 32 bit attenuator settings """ - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT, 32, + self.bus.set_config_mu(SPI_CONFIG | SPI_INPUT, 32, SPIT_ATT_RD, CS_ATT) self.bus.write(0) # shift in zeros, shift out current value - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32, + self.bus.set_config_mu(SPI_CONFIG | SPI_END, 32, SPIT_ATT_WR, CS_ATT) - delay(10 * us) + self.core.delay(10. * us) self.att_reg = self.bus.read() self.bus.write(self.att_reg) # shift in current value again and latch return self.att_reg @kernel - def get_channel_att_mu(self, channel: TInt32) -> TInt32: + def get_channel_att_mu(self, channel: int32) -> int32: """Get digital step attenuator value for a channel in machine units. The result is stored and will be used in future calls of @@ -386,7 +392,7 @@ class CPLD: return int32((self.get_att_mu() >> (channel * 8)) & 0xff) @kernel - def get_channel_att(self, channel: TInt32) -> TFloat: + def get_channel_att(self, channel: int32) -> float: """Get digital step attenuator value for a channel in SI units. .. seealso:: :meth:`get_channel_att_mu` @@ -399,7 +405,7 @@ class CPLD: return self.mu_to_att(self.get_channel_att_mu(channel)) @kernel - def set_sync_div(self, div: TInt32): + def set_sync_div(self, div: int32): """Set the SYNC_IN AD9910 pulse generator frequency and align it to the current RTIO timestamp. @@ -412,11 +418,11 @@ class CPLD: """ ftw_max = 1 << 4 ftw = ftw_max // div - assert ftw * div == ftw_max + # NAC3TODO assert ftw * div == ftw_max self.sync.set_mu(ftw) - @kernel - def set_profile(self, profile: TInt32): + # NAC3TODO @kernel + def set_profile(self, profile: int32): """Set the PROFILE pins. The PROFILE pins are common to all four DDS channels. @@ -426,3 +432,18 @@ class CPLD: cfg = self.cfg_reg & ~(7 << CFG_PROFILE) cfg |= (profile & 7) << CFG_PROFILE self.cfg_write(cfg) + +class _RegIOUpdate: + core: KernelInvariant[Core] + cpld: KernelInvariant[CPLD] + + def __init__(self, core, cpld): + self.core = core + self.cpld = cpld + + @kernel + def pulse(self, t: float): + cfg = self.cpld.cfg_reg + self.cpld.cfg_write(cfg | (1 << CFG_IO_UPDATE)) + delay(t) + self.cpld.cfg_write(cfg) From df87cc88d6b2b5e5f4d97c7475afe434dae82368 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Nov 2021 21:27:06 +0800 Subject: [PATCH 016/352] coredevice/ad9912: port to NAC3 --- artiq/coredevice/ad9912.py | 145 +++++++++++++++++---------------- artiq/coredevice/ad9912_reg.py | 142 ++++++++++++++++---------------- 2 files changed, 148 insertions(+), 139 deletions(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index b214b9496..f1c27077b 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -1,14 +1,16 @@ from numpy import int32, int64 -from artiq.language.types import TInt32, TInt64, TFloat, TTuple, TBool -from artiq.language.core import kernel, delay, portable +from artiq.language.core import KernelInvariant, nac3, kernel, portable from artiq.language.units import ms, us, ns from artiq.coredevice.ad9912_reg import * -from artiq.coredevice import spi2 as spi -from artiq.coredevice import urukul +from artiq.coredevice.core import Core +from artiq.coredevice.spi2 import * +from artiq.coredevice.urukul import * +from artiq.coredevice.ttl import TTLOut +@nac3 class AD9912: """ AD9912 DDS channel on Urukul @@ -27,10 +29,16 @@ class AD9912: instance). """ + core: KernelInvariant[Core] + cpld: KernelInvariant[CPLD] + bus: KernelInvariant[SPIMaster] + chip_select: KernelInvariant[int32] + pll_n: KernelInvariant[int32] + ftw_per_hz: KernelInvariant[float] + sw: KernelInvariant[TTLOut] + def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, pll_n=10): - self.kernel_invariants = {"cpld", "core", "bus", "chip_select", - "pll_n", "ftw_per_hz"} self.cpld = dmgr.get(cpld_device) self.core = self.cpld.core self.bus = self.cpld.bus @@ -38,14 +46,13 @@ class AD9912: self.chip_select = chip_select if sw_device: self.sw = dmgr.get(sw_device) - self.kernel_invariants.add("sw") self.pll_n = pll_n sysclk = self.cpld.refclk / [1, 1, 2, 4][self.cpld.clk_div] * pll_n assert sysclk <= 1e9 - self.ftw_per_hz = 1 / sysclk * (int64(1) << 48) + self.ftw_per_hz = 1 / sysclk * (1 << 48) @kernel - def write(self, addr: TInt32, data: TInt32, length: TInt32): + def write(self, addr: int32, data: int32, length: int32): """Variable length write to a register. Up to 4 bytes. @@ -53,17 +60,17 @@ class AD9912: :param data: Data to be written: int32 :param length: Length in bytes (1-4) """ - assert length > 0 - assert length <= 4 - self.bus.set_config_mu(urukul.SPI_CONFIG, 16, - urukul.SPIT_DDS_WR, self.chip_select) + # NAC3TODO assert length > 0 + # NAC3TODO assert length <= 4 + self.bus.set_config_mu(SPI_CONFIG, 16, + SPIT_DDS_WR, self.chip_select) self.bus.write((addr | ((length - 1) << 13)) << 16) - self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, length * 8, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG | SPI_END, length * 8, + SPIT_DDS_WR, self.chip_select) self.bus.write(data << (32 - length * 8)) @kernel - def read(self, addr: TInt32, length: TInt32) -> TInt32: + def read(self, addr: int32, length: int32) -> int32: """Variable length read from a register. Up to 4 bytes. @@ -71,18 +78,19 @@ class AD9912: :param length: Length in bytes (1-4) :return: Data read """ - assert length > 0 - assert length <= 4 - self.bus.set_config_mu(urukul.SPI_CONFIG, 16, - urukul.SPIT_DDS_WR, self.chip_select) + # NAC3TODO assert length > 0 + # NAC3TODO assert length <= 4 + self.bus.set_config_mu(SPI_CONFIG, 16, + SPIT_DDS_WR, self.chip_select) self.bus.write((addr | ((length - 1) << 13) | 0x8000) << 16) - self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END - | spi.SPI_INPUT, length * 8, - urukul.SPIT_DDS_RD, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG | SPI_END + | SPI_INPUT, length * 8, + SPIT_DDS_RD, self.chip_select) self.bus.write(0) data = self.bus.read() if length < 4: - data &= (1 << (length * 8)) - 1 + # NAC3TODO data &= (1 << (length * 8)) - 1 + data = data & (1 << (length * 8)) - 1 return data @kernel @@ -94,25 +102,26 @@ class AD9912: IO_UPDATE signal multiple times. """ # SPI mode - self.write(AD9912_SER_CONF, 0x99, length=1) - self.cpld.io_update.pulse(2 * us) + self.write(AD9912_SER_CONF, 0x99, 1) + self.cpld.io_update.pulse(2. * us) # Verify chip ID and presence - prodid = self.read(AD9912_PRODIDH, length=2) + prodid = self.read(AD9912_PRODIDH, 2) if (prodid != 0x1982) and (prodid != 0x1902): - raise ValueError("Urukul AD9912 product id mismatch") - delay(50 * us) + # NAC3TODO raise ValueError("Urukul AD9912 product id mismatch") + pass + self.core.delay(50. * us) # HSTL power down, CMOS power down - self.write(AD9912_PWRCNTRL1, 0x80, length=1) - self.cpld.io_update.pulse(2 * us) - self.write(AD9912_N_DIV, self.pll_n // 2 - 2, length=1) - self.cpld.io_update.pulse(2 * us) + self.write(AD9912_PWRCNTRL1, 0x80, 1) + self.cpld.io_update.pulse(2. * us) + self.write(AD9912_N_DIV, self.pll_n // 2 - 2, 1) + self.cpld.io_update.pulse(2. * us) # I_cp = 375 µA, VCO high range - self.write(AD9912_PLLCFG, 0b00000101, length=1) - self.cpld.io_update.pulse(2 * us) - delay(1 * ms) + self.write(AD9912_PLLCFG, 0b00000101, 1) + self.cpld.io_update.pulse(2. * us) + self.core.delay(1. * ms) - @kernel - def set_att_mu(self, att: TInt32): + # NAC3TODO @kernel + def set_att_mu(self, att: int32): """Set digital step attenuator in machine units. This method will write the attenuator settings of all four channels. @@ -123,8 +132,8 @@ class AD9912: """ self.cpld.set_att_mu(self.chip_select - 4, att) - @kernel - def set_att(self, att: TFloat): + # NAC3TODO @kernel + def set_att(self, att: float): """Set digital step attenuator in SI units. This method will write the attenuator settings of all four channels. @@ -136,7 +145,7 @@ class AD9912: self.cpld.set_att(self.chip_select - 4, att) @kernel - def get_att_mu(self) -> TInt32: + def get_att_mu(self) -> int32: """Get digital step attenuator value in machine units. .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.get_channel_att_mu` @@ -146,7 +155,7 @@ class AD9912: return self.cpld.get_channel_att_mu(self.chip_select - 4) @kernel - def get_att(self) -> TFloat: + def get_att(self) -> float: """Get digital step attenuator value in SI units. .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.get_channel_att` @@ -156,7 +165,7 @@ class AD9912: return self.cpld.get_channel_att(self.chip_select - 4) @kernel - def set_mu(self, ftw: TInt64, pow_: TInt32): + def set_mu(self, ftw: int64, pow_: int32): """Set profile 0 data in machine units. After the SPI transfer, the shared IO update pin is pulsed to @@ -166,19 +175,19 @@ class AD9912: :param pow_: Phase tuning word: 16 bit unsigned. """ # streaming transfer of FTW and POW - self.bus.set_config_mu(urukul.SPI_CONFIG, 16, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG, 16, + SPIT_DDS_WR, self.chip_select) self.bus.write((AD9912_POW1 << 16) | (3 << 29)) - self.bus.set_config_mu(urukul.SPI_CONFIG, 32, - urukul.SPIT_DDS_WR, self.chip_select) - self.bus.write((pow_ << 16) | (int32(ftw >> 32) & 0xffff)) - self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG, 32, + SPIT_DDS_WR, self.chip_select) + self.bus.write((pow_ << 16) | (int32(ftw >> int64(32)) & 0xffff)) + self.bus.set_config_mu(SPI_CONFIG | SPI_END, 32, + SPIT_DDS_WR, self.chip_select) self.bus.write(int32(ftw)) - self.cpld.io_update.pulse(10 * ns) + self.cpld.io_update.pulse(10. * ns) @kernel - def get_mu(self) -> TTuple([TInt64, TInt32]): + def get_mu(self) -> tuple[int64, int32]: """Get the frequency tuning word and phase offset word. .. seealso:: :meth:`get` @@ -191,34 +200,34 @@ class AD9912: self.core.break_realtime() # Regain slack to perform second read low = self.read(AD9912_FTW3, 4) # Extract and return fields - ftw = (int64(high & 0xffff) << 32) | (int64(low) & int64(0xffffffff)) + ftw = (int64(high & 0xffff) << int64(32)) | (int64(low) & int64(0xffffffff)) pow_ = (high >> 16) & 0x3fff return ftw, pow_ - @portable(flags={"fast-math"}) - def frequency_to_ftw(self, frequency: TFloat) -> TInt64: + @portable + def frequency_to_ftw(self, frequency: float) -> int64: """Returns the 48-bit frequency tuning word corresponding to the given frequency. """ return int64(round(self.ftw_per_hz * frequency)) & ( - (int64(1) << 48) - 1) + (int64(1) << int64(48)) - int64(1)) - @portable(flags={"fast-math"}) - def ftw_to_frequency(self, ftw: TInt64) -> TFloat: + @portable + def ftw_to_frequency(self, ftw: int64) -> float: """Returns the frequency corresponding to the given frequency tuning word. """ - return ftw / self.ftw_per_hz + return float(ftw) / self.ftw_per_hz - @portable(flags={"fast-math"}) - def turns_to_pow(self, phase: TFloat) -> TInt32: + @portable + def turns_to_pow(self, phase: float) -> int32: """Returns the 16-bit phase offset word corresponding to the given phase. """ - return int32(round((1 << 14) * phase)) & 0xffff + return int32(round(float(1 << 14) * phase)) & 0xffff - @portable(flags={"fast-math"}) - def pow_to_turns(self, pow_: TInt32) -> TFloat: + @portable + def pow_to_turns(self, pow_: int32) -> float: """Return the phase in turns corresponding to a given phase offset word. @@ -228,7 +237,7 @@ class AD9912: return pow_ / (1 << 14) @kernel - def set(self, frequency: TFloat, phase: TFloat = 0.0): + def set(self, frequency: float, phase: float = 0.0): """Set profile 0 data in SI units. .. seealso:: :meth:`set_mu` @@ -240,7 +249,7 @@ class AD9912: self.turns_to_pow(phase)) @kernel - def get(self) -> TTuple([TFloat, TFloat]): + def get(self) -> tuple[float, float]: """Get the frequency and phase. .. seealso:: :meth:`get_mu` @@ -253,8 +262,8 @@ class AD9912: # Convert and return return self.ftw_to_frequency(ftw), self.pow_to_turns(pow_) - @kernel - def cfg_sw(self, state: TBool): + # NAC3TODO @kernel + def cfg_sw(self, state: bool): """Set CPLD CFG RF switch state. The RF switch is controlled by the logical or of the CPLD configuration shift register RF switch bit and the SW TTL line (if used). diff --git a/artiq/coredevice/ad9912_reg.py b/artiq/coredevice/ad9912_reg.py index a85c03ac5..b4555b6ff 100644 --- a/artiq/coredevice/ad9912_reg.py +++ b/artiq/coredevice/ad9912_reg.py @@ -1,78 +1,78 @@ # auto-generated, do not edit +from numpy import int32 from artiq.language.core import portable -from artiq.language.types import TInt32 AD9912_SER_CONF = 0x000 # default: 0x00, access: R/W @portable -def AD9912_SDOACTIVE_SET(x: TInt32) -> TInt32: +def AD9912_SDOACTIVE_SET(x: int32) -> int32: return (x & 0x1) << 0 @portable -def AD9912_SDOACTIVE_GET(x: TInt32) -> TInt32: +def AD9912_SDOACTIVE_GET(x: int32) -> int32: return (x >> 0) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_LSBFIRST_SET(x: TInt32) -> TInt32: +def AD9912_LSBFIRST_SET(x: int32) -> int32: return (x & 0x1) << 1 @portable -def AD9912_LSBFIRST_GET(x: TInt32) -> TInt32: +def AD9912_LSBFIRST_GET(x: int32) -> int32: return (x >> 1) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_SOFTRESET_SET(x: TInt32) -> TInt32: +def AD9912_SOFTRESET_SET(x: int32) -> int32: return (x & 0x1) << 2 @portable -def AD9912_SOFTRESET_GET(x: TInt32) -> TInt32: +def AD9912_SOFTRESET_GET(x: int32) -> int32: return (x >> 2) & 0x1 # default: 0x01, access: R/W @portable -def AD9912_LONGINSN_SET(x: TInt32) -> TInt32: +def AD9912_LONGINSN_SET(x: int32) -> int32: return (x & 0x1) << 3 @portable -def AD9912_LONGINSN_GET(x: TInt32) -> TInt32: +def AD9912_LONGINSN_GET(x: int32) -> int32: return (x >> 3) & 0x1 # default: 0x01, access: R/W @portable -def AD9912_LONGINSN_M_SET(x: TInt32) -> TInt32: +def AD9912_LONGINSN_M_SET(x: int32) -> int32: return (x & 0x1) << 4 @portable -def AD9912_LONGINSN_M_GET(x: TInt32) -> TInt32: +def AD9912_LONGINSN_M_GET(x: int32) -> int32: return (x >> 4) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_SOFTRESET_M_SET(x: TInt32) -> TInt32: +def AD9912_SOFTRESET_M_SET(x: int32) -> int32: return (x & 0x1) << 5 @portable -def AD9912_SOFTRESET_M_GET(x: TInt32) -> TInt32: +def AD9912_SOFTRESET_M_GET(x: int32) -> int32: return (x >> 5) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_LSBFIRST_M_SET(x: TInt32) -> TInt32: +def AD9912_LSBFIRST_M_SET(x: int32) -> int32: return (x & 0x1) << 6 @portable -def AD9912_LSBFIRST_M_GET(x: TInt32) -> TInt32: +def AD9912_LSBFIRST_M_GET(x: int32) -> int32: return (x >> 6) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_SDOACTIVE_M_SET(x: TInt32) -> TInt32: +def AD9912_SDOACTIVE_M_SET(x: int32) -> int32: return (x & 0x1) << 7 @portable -def AD9912_SDOACTIVE_M_GET(x: TInt32) -> TInt32: +def AD9912_SDOACTIVE_M_GET(x: int32) -> int32: return (x >> 7) & 0x1 @@ -83,118 +83,118 @@ AD9912_PRODIDH = 0x003 AD9912_SER_OPT1 = 0x004 # default: 0x00, access: R/W @portable -def AD9912_READ_BUF_SET(x: TInt32) -> TInt32: +def AD9912_READ_BUF_SET(x: int32) -> int32: return (x & 0x1) << 0 @portable -def AD9912_READ_BUF_GET(x: TInt32) -> TInt32: +def AD9912_READ_BUF_GET(x: int32) -> int32: return (x >> 0) & 0x1 AD9912_SER_OPT2 = 0x005 # default: 0x00, access: R/W @portable -def AD9912_RED_UPDATE_SET(x: TInt32) -> TInt32: +def AD9912_RED_UPDATE_SET(x: int32) -> int32: return (x & 0x1) << 0 @portable -def AD9912_RED_UPDATE_GET(x: TInt32) -> TInt32: +def AD9912_RED_UPDATE_GET(x: int32) -> int32: return (x >> 0) & 0x1 AD9912_PWRCNTRL1 = 0x010 # default: 0x00, access: R/W @portable -def AD9912_PD_DIGITAL_SET(x: TInt32) -> TInt32: +def AD9912_PD_DIGITAL_SET(x: int32) -> int32: return (x & 0x1) << 0 @portable -def AD9912_PD_DIGITAL_GET(x: TInt32) -> TInt32: +def AD9912_PD_DIGITAL_GET(x: int32) -> int32: return (x >> 0) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_PD_FULL_SET(x: TInt32) -> TInt32: +def AD9912_PD_FULL_SET(x: int32) -> int32: return (x & 0x1) << 1 @portable -def AD9912_PD_FULL_GET(x: TInt32) -> TInt32: +def AD9912_PD_FULL_GET(x: int32) -> int32: return (x >> 1) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_PD_SYSCLK_SET(x: TInt32) -> TInt32: +def AD9912_PD_SYSCLK_SET(x: int32) -> int32: return (x & 0x1) << 4 @portable -def AD9912_PD_SYSCLK_GET(x: TInt32) -> TInt32: +def AD9912_PD_SYSCLK_GET(x: int32) -> int32: return (x >> 4) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_EN_DOUBLER_SET(x: TInt32) -> TInt32: +def AD9912_EN_DOUBLER_SET(x: int32) -> int32: return (x & 0x1) << 5 @portable -def AD9912_EN_DOUBLER_GET(x: TInt32) -> TInt32: +def AD9912_EN_DOUBLER_GET(x: int32) -> int32: return (x >> 5) & 0x1 # default: 0x01, access: R/W @portable -def AD9912_EN_CMOS_SET(x: TInt32) -> TInt32: +def AD9912_EN_CMOS_SET(x: int32) -> int32: return (x & 0x1) << 6 @portable -def AD9912_EN_CMOS_GET(x: TInt32) -> TInt32: +def AD9912_EN_CMOS_GET(x: int32) -> int32: return (x >> 6) & 0x1 # default: 0x01, access: R/W @portable -def AD9912_PD_HSTL_SET(x: TInt32) -> TInt32: +def AD9912_PD_HSTL_SET(x: int32) -> int32: return (x & 0x1) << 7 @portable -def AD9912_PD_HSTL_GET(x: TInt32) -> TInt32: +def AD9912_PD_HSTL_GET(x: int32) -> int32: return (x >> 7) & 0x1 AD9912_PWRCNTRL2 = 0x012 # default: 0x00, access: R/W @portable -def AD9912_DDS_RESET_SET(x: TInt32) -> TInt32: +def AD9912_DDS_RESET_SET(x: int32) -> int32: return (x & 0x1) << 0 @portable -def AD9912_DDS_RESET_GET(x: TInt32) -> TInt32: +def AD9912_DDS_RESET_GET(x: int32) -> int32: return (x >> 0) & 0x1 AD9912_PWRCNTRL3 = 0x013 # default: 0x00, access: R/W @portable -def AD9912_S_DIV_RESET_SET(x: TInt32) -> TInt32: +def AD9912_S_DIV_RESET_SET(x: int32) -> int32: return (x & 0x1) << 1 @portable -def AD9912_S_DIV_RESET_GET(x: TInt32) -> TInt32: +def AD9912_S_DIV_RESET_GET(x: int32) -> int32: return (x >> 1) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_S_DIV2_RESET_SET(x: TInt32) -> TInt32: +def AD9912_S_DIV2_RESET_SET(x: int32) -> int32: return (x & 0x1) << 3 @portable -def AD9912_S_DIV2_RESET_GET(x: TInt32) -> TInt32: +def AD9912_S_DIV2_RESET_GET(x: int32) -> int32: return (x >> 3) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_PD_FUND_SET(x: TInt32) -> TInt32: +def AD9912_PD_FUND_SET(x: int32) -> int32: return (x & 0x1) << 7 @portable -def AD9912_PD_FUND_GET(x: TInt32) -> TInt32: +def AD9912_PD_FUND_GET(x: int32) -> int32: return (x >> 7) & 0x1 @@ -203,38 +203,38 @@ AD9912_N_DIV = 0x020 AD9912_PLLCFG = 0x022 # default: 0x00, access: R/W @portable -def AD9912_PLL_ICP_SET(x: TInt32) -> TInt32: +def AD9912_PLL_ICP_SET(x: int32) -> int32: return (x & 0x3) << 0 @portable -def AD9912_PLL_ICP_GET(x: TInt32) -> TInt32: +def AD9912_PLL_ICP_GET(x: int32) -> int32: return (x >> 0) & 0x3 # default: 0x01, access: R/W @portable -def AD9912_VCO_RANGE_SET(x: TInt32) -> TInt32: +def AD9912_VCO_RANGE_SET(x: int32) -> int32: return (x & 0x1) << 2 @portable -def AD9912_VCO_RANGE_GET(x: TInt32) -> TInt32: +def AD9912_VCO_RANGE_GET(x: int32) -> int32: return (x >> 2) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_PLL_REF2X_SET(x: TInt32) -> TInt32: +def AD9912_PLL_REF2X_SET(x: int32) -> int32: return (x & 0x1) << 3 @portable -def AD9912_PLL_REF2X_GET(x: TInt32) -> TInt32: +def AD9912_PLL_REF2X_GET(x: int32) -> int32: return (x >> 3) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_VCO_AUTO_RANGE_SET(x: TInt32) -> TInt32: +def AD9912_VCO_AUTO_RANGE_SET(x: int32) -> int32: return (x & 0x1) << 7 @portable -def AD9912_VCO_AUTO_RANGE_GET(x: TInt32) -> TInt32: +def AD9912_VCO_AUTO_RANGE_GET(x: int32) -> int32: return (x >> 7) & 0x1 @@ -245,20 +245,20 @@ AD9912_S_DIVH = 0x105 AD9912_S_DIV_CFG = 0x106 # default: 0x01, access: R/W @portable -def AD9912_S_DIV2_SET(x: TInt32) -> TInt32: +def AD9912_S_DIV2_SET(x: int32) -> int32: return (x & 0x1) << 0 @portable -def AD9912_S_DIV2_GET(x: TInt32) -> TInt32: +def AD9912_S_DIV2_GET(x: int32) -> int32: return (x >> 0) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_S_DIV_FALL_SET(x: TInt32) -> TInt32: +def AD9912_S_DIV_FALL_SET(x: int32) -> int32: return (x & 0x1) << 7 @portable -def AD9912_S_DIV_FALL_GET(x: TInt32) -> TInt32: +def AD9912_S_DIV_FALL_GET(x: int32) -> int32: return (x >> 7) & 0x1 @@ -281,31 +281,31 @@ AD9912_POW1 = 0x1ad AD9912_HSTL = 0x200 # default: 0x01, access: R/W @portable -def AD9912_HSTL_CFG_SET(x: TInt32) -> TInt32: +def AD9912_HSTL_CFG_SET(x: int32) -> int32: return (x & 0x3) << 0 @portable -def AD9912_HSTL_CFG_GET(x: TInt32) -> TInt32: +def AD9912_HSTL_CFG_GET(x: int32) -> int32: return (x >> 0) & 0x3 # default: 0x01, access: R/W @portable -def AD9912_HSTL_OPOL_SET(x: TInt32) -> TInt32: +def AD9912_HSTL_OPOL_SET(x: int32) -> int32: return (x & 0x1) << 4 @portable -def AD9912_HSTL_OPOL_GET(x: TInt32) -> TInt32: +def AD9912_HSTL_OPOL_GET(x: int32) -> int32: return (x >> 4) & 0x1 AD9912_CMOS = 0x201 # default: 0x00, access: R/W @portable -def AD9912_CMOS_MUX_SET(x: TInt32) -> TInt32: +def AD9912_CMOS_MUX_SET(x: int32) -> int32: return (x & 0x1) << 0 @portable -def AD9912_CMOS_MUX_GET(x: TInt32) -> TInt32: +def AD9912_CMOS_MUX_GET(x: int32) -> int32: return (x >> 0) & 0x1 @@ -316,29 +316,29 @@ AD9912_FSC1 = 0x40c AD9912_HSR_A_CFG = 0x500 # default: 0x00, access: R/W @portable -def AD9912_HSR_A_HARMONIC_SET(x: TInt32) -> TInt32: +def AD9912_HSR_A_HARMONIC_SET(x: int32) -> int32: return (x & 0xf) << 0 @portable -def AD9912_HSR_A_HARMONIC_GET(x: TInt32) -> TInt32: +def AD9912_HSR_A_HARMONIC_GET(x: int32) -> int32: return (x >> 0) & 0xf # default: 0x00, access: R/W @portable -def AD9912_HSR_A_MAG2X_SET(x: TInt32) -> TInt32: +def AD9912_HSR_A_MAG2X_SET(x: int32) -> int32: return (x & 0x1) << 6 @portable -def AD9912_HSR_A_MAG2X_GET(x: TInt32) -> TInt32: +def AD9912_HSR_A_MAG2X_GET(x: int32) -> int32: return (x >> 6) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_HSR_A_EN_SET(x: TInt32) -> TInt32: +def AD9912_HSR_A_EN_SET(x: int32) -> int32: return (x & 0x1) << 7 @portable -def AD9912_HSR_A_EN_GET(x: TInt32) -> TInt32: +def AD9912_HSR_A_EN_GET(x: int32) -> int32: return (x >> 7) & 0x1 @@ -351,29 +351,29 @@ AD9912_HSR_A_POW1 = 0x504 AD9912_HSR_B_CFG = 0x505 # default: 0x00, access: R/W @portable -def AD9912_HSR_B_HARMONIC_SET(x: TInt32) -> TInt32: +def AD9912_HSR_B_HARMONIC_SET(x: int32) -> int32: return (x & 0xf) << 0 @portable -def AD9912_HSR_B_HARMONIC_GET(x: TInt32) -> TInt32: +def AD9912_HSR_B_HARMONIC_GET(x: int32) -> int32: return (x >> 0) & 0xf # default: 0x00, access: R/W @portable -def AD9912_HSR_B_MAG2X_SET(x: TInt32) -> TInt32: +def AD9912_HSR_B_MAG2X_SET(x: int32) -> int32: return (x & 0x1) << 6 @portable -def AD9912_HSR_B_MAG2X_GET(x: TInt32) -> TInt32: +def AD9912_HSR_B_MAG2X_GET(x: int32) -> int32: return (x >> 6) & 0x1 # default: 0x00, access: R/W @portable -def AD9912_HSR_B_EN_SET(x: TInt32) -> TInt32: +def AD9912_HSR_B_EN_SET(x: int32) -> int32: return (x & 0x1) << 7 @portable -def AD9912_HSR_B_EN_GET(x: TInt32) -> TInt32: +def AD9912_HSR_B_EN_GET(x: int32) -> int32: return (x >> 7) & 0x1 From a8129093df2ba1e3b8369bbc811cb55a5af26574 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Nov 2021 21:31:03 +0800 Subject: [PATCH 017/352] artiq_run: port to NAC3 (WIP) --- artiq/frontend/artiq_run.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index e29eef8d1..60a85e664 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -14,11 +14,8 @@ from sipyco import common_args from artiq import __version__ as artiq_version from artiq.language.environment import EnvExperiment, ProcessArgumentManager -from artiq.language.types import TBool from artiq.master.databases import DeviceDB, DatasetDB from artiq.master.worker_db import DeviceManager, DatasetManager -from artiq.coredevice.core import CompileError, host_only -from artiq.compiler.embedding import EmbeddingMap from artiq.compiler import import_cache from artiq.tools import * @@ -92,10 +89,9 @@ class DummyScheduler: def get_status(self): return dict() - def check_pause(self, rid=None) -> TBool: + def check_pause(self, rid=None) -> bool: return False - @host_only def pause(self): pass @@ -178,8 +174,6 @@ def run(with_file=False): exp_inst.prepare() exp_inst.run() exp_inst.analyze() - except CompileError as error: - return except Exception as exn: if hasattr(exn, "artiq_core_exception"): print(exn.artiq_core_exception, file=sys.stderr) From c7cca11ad140b8ff013cf22beaaab58ebc0abedb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 11 Nov 2021 16:32:37 +0800 Subject: [PATCH 018/352] update NAC3 --- artiq/coredevice/core.py | 6 +++--- artiq/language/core.py | 27 ++++++++++++++++----------- flake.lock | 8 ++++---- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 766ff0cef..fa332858e 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -60,9 +60,9 @@ class Core: self.comm.close() def compile(self, method, args, kwargs, file_output=None): - if core_language._allow_module_registration: - self.compiler.analyze_modules(core_language._registered_modules) - core_language._allow_module_registration = False + if core_language._allow_registration: + self.compiler.analyze(core_language._registered_functions, core_language._registered_classes) + core_language._allow_registration = False if hasattr(method, "__self__"): obj = method.__self__ diff --git a/artiq/language/core.py b/artiq/language/core.py index 36d8b459e..c6a96ecbe 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -4,7 +4,7 @@ Core ARTIQ extensions to the Python language. from typing import Generic, TypeVar from functools import wraps -from inspect import getfullargspec, getmodule +from inspect import getfullargspec from types import SimpleNamespace @@ -25,24 +25,29 @@ def round64(x): return round(x) -_allow_module_registration = True -_registered_modules = set() +_allow_registration = True +# Delay NAC3 analysis until all referenced variables are supposed to exist on the CPython side. +_registered_functions = set() +_registered_classes = set() -def _register_module_of(obj): - assert _allow_module_registration - # Delay NAC3 analysis until all referenced variables are supposed to exist on the CPython side. - _registered_modules.add(getmodule(obj)) +def _register_function(fun): + assert _allow_registration + _registered_functions.add(fun) + +def _register_class(cls): + assert _allow_registration + _registered_classes.add(cls) def extern(function): """Decorates a function declaration defined by the core device runtime.""" - _register_module_of(function) + _register_function(function) return function def kernel(function_or_method): """Decorates a function or method to be executed on the core device.""" - _register_module_of(function_or_method) + _register_function(function_or_method) argspec = getfullargspec(function_or_method) if argspec.args and argspec.args[0] == "self": @wraps(function_or_method) @@ -59,7 +64,7 @@ def kernel(function_or_method): def portable(function): """Decorates a function or method to be executed on the same device (host/core device) as the caller.""" - _register_module_of(function) + _register_function(function) return function @@ -68,7 +73,7 @@ def nac3(cls): Decorates a class to be analyzed by NAC3. All classes containing kernels or portable methods must use this decorator. """ - _register_module_of(cls) + _register_class(cls) return cls diff --git a/flake.lock b/flake.lock index 36927591b..5619ab884 100644 --- a/flake.lock +++ b/flake.lock @@ -82,11 +82,11 @@ ] }, "locked": { - "lastModified": 1636252154, - "narHash": "sha256-YPRjk9M9GdUiAZircxUl5BDU8rN5t0B0ZkIau+dMqmg=", + "lastModified": 1636618109, + "narHash": "sha256-dJu9Tw+8mVL3ZMIlcvM9g6WT3hYrKDaVceZJV+BxjTA=", "ref": "master", - "rev": "50f1aca1aa7ecb4412aa4b8a0daa1cc644d8ca89", - "revCount": 412, + "rev": "c004da85f705fef8952885c1493407610a05b61d", + "revCount": 415, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 64c180c9e7db6e6fdb01d163d475244900053a06 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 11 Nov 2021 16:51:56 +0800 Subject: [PATCH 019/352] update NAC3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 5619ab884..8f8b53624 100644 --- a/flake.lock +++ b/flake.lock @@ -82,11 +82,11 @@ ] }, "locked": { - "lastModified": 1636618109, - "narHash": "sha256-dJu9Tw+8mVL3ZMIlcvM9g6WT3hYrKDaVceZJV+BxjTA=", + "lastModified": 1636619740, + "narHash": "sha256-hJP4hjn9z2Mj/2I3jWZqqvUIOGGfmAKmmN6F8HegC4Y=", "ref": "master", - "rev": "c004da85f705fef8952885c1493407610a05b61d", - "revCount": 415, + "rev": "612b6768c0b0099d8b1bbd4f51014bc0cacba0b6", + "revCount": 416, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 5a3bf4894fc5fb4dae36751434cbeee3bc63361f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 11 Nov 2021 20:35:06 +0800 Subject: [PATCH 020/352] reinstate import_cache hack (#416) --- artiq/frontend/artiq_run.py | 2 +- artiq/language/__init__.py | 3 +- artiq/language/core.py | 6 +++- artiq/language/import_cache.py | 52 ++++++++++++++++++++++++++++++++++ artiq/master/worker_impl.py | 2 +- 5 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 artiq/language/import_cache.py diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index 60a85e664..45ee1f34d 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -16,7 +16,7 @@ from artiq import __version__ as artiq_version from artiq.language.environment import EnvExperiment, ProcessArgumentManager from artiq.master.databases import DeviceDB, DatasetDB from artiq.master.worker_db import DeviceManager, DatasetManager -from artiq.compiler import import_cache +from artiq.language import import_cache from artiq.tools import * diff --git a/artiq/language/__init__.py b/artiq/language/__init__.py index fef1a93ca..99c019a75 100644 --- a/artiq/language/__init__.py +++ b/artiq/language/__init__.py @@ -3,8 +3,9 @@ from artiq.language.core import * from artiq.language.environment import * from artiq.language.units import * from artiq.language.scan import * +from . import import_cache -__all__ = [] +__all__ = ["import_cache"] __all__.extend(core.__all__) __all__.extend(environment.__all__) __all__.extend(units.__all__) diff --git a/artiq/language/core.py b/artiq/language/core.py index c6a96ecbe..ba3c91083 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -4,9 +4,11 @@ Core ARTIQ extensions to the Python language. from typing import Generic, TypeVar from functools import wraps -from inspect import getfullargspec +from inspect import getfullargspec, getmodule from types import SimpleNamespace +from artiq.language import import_cache + __all__ = [ "KernelInvariant", "round64", @@ -32,10 +34,12 @@ _registered_classes = set() def _register_function(fun): assert _allow_registration + import_cache.add_module_to_cache(getmodule(fun)) _registered_functions.add(fun) def _register_class(cls): assert _allow_registration + import_cache.add_module_to_cache(getmodule(cls)) _registered_classes.add(cls) diff --git a/artiq/language/import_cache.py b/artiq/language/import_cache.py new file mode 100644 index 000000000..08de378c4 --- /dev/null +++ b/artiq/language/import_cache.py @@ -0,0 +1,52 @@ +""" +Caches source files on import so that inspect.getsource returns the source code that +was imported (or at least with a small race window), not what is currently on the +filesystem at the time inspect.getsource is called. +This is a hack and it still has races, and it would be better if Python supported +this correctly, but it does not. +""" + +import linecache +import tokenize +import logging + + +__all__ = ["install_hook", "add_module_to_cache"] + + +logger = logging.getLogger(__name__) + + +cache = dict() +linecache_getlines = None + + +def add_module_to_cache(module): + if hasattr(module, "__file__"): + fn = module.__file__ + try: + with tokenize.open(fn) as fp: + lines = fp.readlines() + if lines and not lines[-1].endswith("\n"): + lines[-1] += "\n" + cache[fn] = lines + except: + logger.warning("failed to add '%s' to cache", fn, exc_info=True) + else: + logger.debug("added '%s' to cache", fn) + + +def hook_getlines(filename, module_globals=None): + if filename in cache: + return cache[filename] + else: + return linecache_getlines(filename, module_globals) + + +def install_hook(): + global linecache_getlines + + linecache_getlines = linecache.getlines + linecache.getlines = hook_getlines + + logger.debug("hook installed") diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 0467a8096..29ec4e427 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -28,7 +28,7 @@ from artiq.language.environment import ( ) from artiq.language.core import set_watchdog_factory, TerminationRequested from artiq.language.types import TBool -from artiq.compiler import import_cache +from artiq.language import import_cache from artiq.coredevice.core import CompileError, host_only, _render_diagnostic from artiq import __version__ as artiq_version From 1ea3cf48d644b38190b3cc7c1060e885208857fb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 11 Nov 2021 20:35:45 +0800 Subject: [PATCH 021/352] fix core.run invokation --- artiq/language/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/language/core.py b/artiq/language/core.py index ba3c91083..b4934dc3e 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -57,7 +57,7 @@ def kernel(function_or_method): @wraps(function_or_method) def run_on_core(self, *args, **kwargs): fake_method = SimpleNamespace(__self__=self, __name__=function_or_method.__name__) - self.core.run(fake_method, *args, **kwargs) + self.core.run(fake_method, args, kwargs) else: @wraps(function_or_method) def run_on_core(*args, **kwargs): From 95eb2181122724bd4ebaca9fd7f5d6e22c47e0b2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 11 Nov 2021 20:42:49 +0800 Subject: [PATCH 022/352] import_cache: read files only once --- artiq/language/import_cache.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/artiq/language/import_cache.py b/artiq/language/import_cache.py index 08de378c4..8ccc8d6ba 100644 --- a/artiq/language/import_cache.py +++ b/artiq/language/import_cache.py @@ -24,16 +24,17 @@ linecache_getlines = None def add_module_to_cache(module): if hasattr(module, "__file__"): fn = module.__file__ - try: - with tokenize.open(fn) as fp: - lines = fp.readlines() - if lines and not lines[-1].endswith("\n"): - lines[-1] += "\n" - cache[fn] = lines - except: - logger.warning("failed to add '%s' to cache", fn, exc_info=True) - else: - logger.debug("added '%s' to cache", fn) + if fn not in cache: + try: + with tokenize.open(fn) as fp: + lines = fp.readlines() + if lines and not lines[-1].endswith("\n"): + lines[-1] += "\n" + cache[fn] = lines + except: + logger.warning("failed to add '%s' to cache", fn, exc_info=True) + else: + logger.debug("added '%s' to cache", fn) def hook_getlines(filename, module_globals=None): From f07c747fa79e1b6263f6270e6c4ea94121dfbf82 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 12 Nov 2021 16:27:08 +0800 Subject: [PATCH 023/352] flake: update nac3, use patched nixpkgs from nac3 --- flake.lock | 34 ++++++++++++++++------------------ flake.nix | 7 +++---- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/flake.lock b/flake.lock index 8f8b53624..ce8d04b6a 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1634833229, - "narHash": "sha256-uDbVCkW91/AY87mTwm8XrX2E133LTFqwYsYNNxBcY9M=", + "lastModified": 1636569584, + "narHash": "sha256-iDFogua24bhFJZSxG/jhZbbNxDXuKP9S/pyRIYzrRPM=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "6070a8ee799f629cb1d0004821f77ceed94d3992", + "rev": "9f70f86d73fa97e043bebeb58e5676d157069cfb", "type": "github" }, "original": { @@ -18,15 +18,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1635946136, - "narHash": "sha256-y1l0FK/nyRqb9CCImHNDJYYTtCnSNF2rK5RFc+qaMEg=", + "lastModified": 1636698608, + "narHash": "sha256-sxLLeQmH3UrP3UANqXzMLE0bPDgY5aIt04iBoPffG2E=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8429ae8722a319ebc26e9a38105e0797a824eb87", + "rev": "92c881b6a72abce5bb2f5db3f903b4871d13aaa9", "type": "github" }, "original": { "owner": "NixOS", + "ref": "master", "repo": "nixpkgs", "type": "github" } @@ -34,7 +35,6 @@ "root": { "inputs": { "mozilla-overlay": "mozilla-overlay", - "nixpkgs": "nixpkgs", "src-migen": "src-migen", "src-misoc": "src-misoc", "src-nac3": "src-nac3", @@ -60,11 +60,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1635235511, - "narHash": "sha256-XdBMBfup7JbUPzBi0An8GnQCIp7tiaczTrOwsPpvKCM=", + "lastModified": 1636527305, + "narHash": "sha256-/2XTejqj0Bo81HaTrlTSWwInnWwsuqnq+CURXbpIrkA=", "ref": "master", - "rev": "34e545c190e08ada3f59712bdb71208ac6c39cbc", - "revCount": 2397, + "rev": "f5203e406520874e15ab5d070058ef642fc57fd9", + "revCount": 2417, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" @@ -77,16 +77,14 @@ }, "src-nac3": { "inputs": { - "nixpkgs": [ - "nixpkgs" - ] + "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1636619740, - "narHash": "sha256-hJP4hjn9z2Mj/2I3jWZqqvUIOGGfmAKmmN6F8HegC4Y=", + "lastModified": 1636703241, + "narHash": "sha256-5Bm5+4YctgGGrX8ncZVDJ5LONKIFyGjqQexWLCGUI9k=", "ref": "master", - "rev": "612b6768c0b0099d8b1bbd4f51014bc0cacba0b6", - "revCount": 416, + "rev": "aa84fefa5629d1367a00d5703dd2f0b7ee7c26b0", + "revCount": 426, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, diff --git a/flake.nix b/flake.nix index ada7bab88..c68745836 100644 --- a/flake.nix +++ b/flake.nix @@ -1,17 +1,16 @@ { description = "A leading-edge control system for quantum information experiments"; - inputs.nixpkgs.url = github:NixOS/nixpkgs; inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; }; inputs.src-sipyco = { url = github:m-labs/sipyco; flake = false; }; - inputs.src-nac3 = { type = "git"; url = "https://git.m-labs.hk/M-Labs/nac3.git"; inputs.nixpkgs.follows = "nixpkgs"; }; + inputs.src-nac3 = { type = "git"; url = "https://git.m-labs.hk/M-Labs/nac3.git"; }; inputs.src-migen = { url = github:m-labs/migen; flake = false; }; inputs.src-misoc = { type = "git"; url = "https://github.com/m-labs/misoc.git"; submodules = true; flake = false; }; - outputs = { self, nixpkgs, mozilla-overlay, src-sipyco, src-nac3, src-migen, src-misoc }: + outputs = { self, mozilla-overlay, src-sipyco, src-nac3, src-migen, src-misoc }: let - pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; }; + pkgs = import src-nac3.nixpkgs-patched { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; }; rustManifest = pkgs.fetchurl { url = "https://static.rust-lang.org/dist/2021-01-29/channel-rust-nightly.toml"; sha256 = "sha256-EZKgw89AH4vxaJpUHmIMzMW/80wAFQlfcxRoBD9nz0c="; From 38e554fe9803b73454461eb26eef4a5c77d25a55 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 12 Nov 2021 19:57:48 +0800 Subject: [PATCH 024/352] artiq_run: fix ELF handling --- artiq/frontend/artiq_run.py | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index 45ee1f34d..e8c6d86e8 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -23,40 +23,17 @@ from artiq.tools import * logger = logging.getLogger(__name__) -class StubObject: - def __setattr__(self, name, value): - pass - - -class StubEmbeddingMap: - def __init__(self): - stub_object = StubObject() - self.object_forward_map = defaultdict(lambda: stub_object) - self.object_forward_map[1] = lambda _: None # return RPC - self.object_current_id = -1 - - def retrieve_object(self, object_id): - return self.object_forward_map[object_id] - - def store_object(self, value): - self.object_forward_map[self.object_current_id] = value - self.object_current_id -= 1 - - class FileRunner(EnvExperiment): def build(self, file): self.setattr_device("core") self.file = file - self.target = self.core.target_cls() def run(self): kernel_library = self.compile() self.core.comm.load(kernel_library) self.core.comm.run() - self.core.comm.serve(StubEmbeddingMap(), - lambda addresses: self.target.symbolize(kernel_library, addresses), \ - lambda symbols: self.target.demangle(symbols)) + self.core.comm.serve(None, None, None) class ELFRunner(FileRunner): From 3f807ad19e8ecd8385eb8d7ad12a6d0ac3c60174 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 12 Nov 2021 20:07:29 +0800 Subject: [PATCH 025/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 6e78e6775..948ddc5dc 100644 --- a/flake.lock +++ b/flake.lock @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1636703241, - "narHash": "sha256-5Bm5+4YctgGGrX8ncZVDJ5LONKIFyGjqQexWLCGUI9k=", + "lastModified": 1636718632, + "narHash": "sha256-MnLHFFT2m1FI/LZIg39yTRhnwAMgCxRgzYZpmmMTy6M=", "ref": "master", - "rev": "aa84fefa5629d1367a00d5703dd2f0b7ee7c26b0", - "revCount": 426, + "rev": "d6b92adf70369a46e15aae7f9213006814219c49", + "revCount": 427, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 7a2428b6a7314631405e69703e20bee6a31a9a31 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 13 Nov 2021 12:33:07 +0800 Subject: [PATCH 026/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 948ddc5dc..74801619b 100644 --- a/flake.lock +++ b/flake.lock @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1636718632, - "narHash": "sha256-MnLHFFT2m1FI/LZIg39yTRhnwAMgCxRgzYZpmmMTy6M=", + "lastModified": 1636777462, + "narHash": "sha256-8XdQsKNno0HS5h0dxGXXzvpR0rsnTGgOL9Vpi7GdLik=", "ref": "master", - "rev": "d6b92adf70369a46e15aae7f9213006814219c49", - "revCount": 427, + "rev": "8ab3ee9cce58861eaf56c0d9b08805ccfcbace01", + "revCount": 429, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 222968d68b0b63dc8b5cd209ed2743a55c759343 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 13 Nov 2021 12:42:13 +0800 Subject: [PATCH 027/352] coredevice: reinstate AugAssign methods --- artiq/coredevice/ad9912.py | 9 ++++----- artiq/coredevice/ttl.py | 2 +- artiq/coredevice/urukul.py | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index f1c27077b..d8e35898f 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -89,8 +89,7 @@ class AD9912: self.bus.write(0) data = self.bus.read() if length < 4: - # NAC3TODO data &= (1 << (length * 8)) - 1 - data = data & (1 << (length * 8)) - 1 + data &= (1 << (length * 8)) - 1 return data @kernel @@ -120,7 +119,7 @@ class AD9912: self.cpld.io_update.pulse(2. * us) self.core.delay(1. * ms) - # NAC3TODO @kernel + @kernel def set_att_mu(self, att: int32): """Set digital step attenuator in machine units. @@ -132,7 +131,7 @@ class AD9912: """ self.cpld.set_att_mu(self.chip_select - 4, att) - # NAC3TODO @kernel + @kernel def set_att(self, att: float): """Set digital step attenuator in SI units. @@ -262,7 +261,7 @@ class AD9912: # Convert and return return self.ftw_to_frequency(ftw), self.pow_to_turns(pow_) - # NAC3TODO @kernel + @kernel def cfg_sw(self, state: bool): """Set CPLD CFG RF switch state. The RF switch is controlled by the logical or of the CPLD configuration shift register diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 0aec996da..45c3d6fe9 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -307,7 +307,7 @@ class TTLInOut: self._set_sensitivity(0) return now_mu() - # NAC3TODO @kernel + @kernel def count(self, up_to_timestamp_mu: int64) -> int32: """Consume RTIO input events until the hardware timestamp counter has reached the specified timestamp and return the number of observed diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index f329f0df7..21c3bbf34 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -265,7 +265,7 @@ class CPLD: self.cfg_write(self.cfg_reg | (1 << CFG_IO_RST)) self.cfg_write(self.cfg_reg & ~(1 << CFG_IO_RST)) - # NAC3TODO @kernel + @kernel def cfg_sw(self, channel: int32, on: bool): """Configure the RF switches through the configuration register. @@ -311,7 +311,7 @@ class CPLD: pass return code - # NAC3TODO @kernel + @kernel def set_att_mu(self, channel: int32, att: int32): """Set digital step attenuator in machine units. @@ -340,7 +340,7 @@ class CPLD: self.bus.write(att_reg) self.att_reg = att_reg - # NAC3TODO @kernel + @kernel def set_att(self, channel: int32, att: float): """Set digital step attenuator in SI units. @@ -421,7 +421,7 @@ class CPLD: # NAC3TODO assert ftw * div == ftw_max self.sync.set_mu(ftw) - # NAC3TODO @kernel + @kernel def set_profile(self, profile: int32): """Set the PROFILE pins. From 01f21f7545c4f103af977b038933257d224facee Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 16 Nov 2021 17:51:18 +0800 Subject: [PATCH 028/352] flake: update dependencies --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 74801619b..c99b82aa7 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1636569584, - "narHash": "sha256-iDFogua24bhFJZSxG/jhZbbNxDXuKP9S/pyRIYzrRPM=", + "lastModified": 1636992969, + "narHash": "sha256-N1DBtHSrN2usDeDYD6IcnAUcMfc+i+UKv0U/+j7n5HY=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "9f70f86d73fa97e043bebeb58e5676d157069cfb", + "rev": "4c8fc3d7b625d2d34bfb5aedf03c131aef2f87f8", "type": "github" }, "original": { @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1636777462, - "narHash": "sha256-8XdQsKNno0HS5h0dxGXXzvpR0rsnTGgOL9Vpi7GdLik=", + "lastModified": 1637055460, + "narHash": "sha256-XMPoYABsiakMoQnFgBSRkFkSAS8TFZDxfDrpGfdKL9k=", "ref": "master", - "rev": "8ab3ee9cce58861eaf56c0d9b08805ccfcbace01", - "revCount": 429, + "rev": "1e47b364c5ba3a60d7715faae496fe4c24011591", + "revCount": 430, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From f4acf04405c69376e34e04b444b7be82ea0cf265 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 16 Nov 2021 18:32:14 +0800 Subject: [PATCH 029/352] coredevice: fix run method --- artiq/coredevice/core.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 97cd9ed59..966838572 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -84,7 +84,6 @@ class Core: self.comm.load(kernel_library) self.comm.run() self.comm.serve(None, None, None) - return result @portable def seconds_to_mu(self, seconds: float) -> int64: From cc1080e0553e997935d631d62188c7a8f8645652 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 19 Nov 2021 12:42:08 +0800 Subject: [PATCH 030/352] ad9912: fix frequency_to_ftw --- artiq/coredevice/ad9912.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index d8e35898f..5c294d1de 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -208,7 +208,7 @@ class AD9912: """Returns the 48-bit frequency tuning word corresponding to the given frequency. """ - return int64(round(self.ftw_per_hz * frequency)) & ( + return round64(self.ftw_per_hz * frequency) & ( (int64(1) << int64(48)) - int64(1)) @portable From aa5f667ad8fce84dd7ccf9dba8c01214f77bbd40 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 19 Nov 2021 12:47:52 +0800 Subject: [PATCH 031/352] ad9912: increase slack (no kernel invariants in NAC3 yet?) --- artiq/coredevice/ad9912.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 5c294d1de..2be434d45 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -108,7 +108,7 @@ class AD9912: if (prodid != 0x1982) and (prodid != 0x1902): # NAC3TODO raise ValueError("Urukul AD9912 product id mismatch") pass - self.core.delay(50. * us) + self.core.delay(300. * us) # NAC3TODO try to restore 50us after kernel invariants are implemented # HSTL power down, CMOS power down self.write(AD9912_PWRCNTRL1, 0x80, 1) self.cpld.io_update.pulse(2. * us) From 64877c0588d254231e16cf195c7fcdc263fbf564 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 19 Nov 2021 18:18:24 +0800 Subject: [PATCH 032/352] fix Python 3.9 compatibility --- artiq/gateware/targets/kasli_generic.py | 4 ++-- versioneer.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index 122c3e0cf..fa02f072c 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -2,7 +2,7 @@ import argparse import logging -from distutils.version import LooseVersion +from packaging import version from misoc.integration.builder import builder_args, builder_argdict from misoc.targets.kasli import soc_kasli_args, soc_kasli_argdict @@ -150,7 +150,7 @@ def main(): description = jsondesc.load(args.description) min_artiq_version = description.get("min_artiq_version", "0") - if LooseVersion(artiq_version) < LooseVersion(min_artiq_version): + if version.parse(artiq_version) < version.parse(min_artiq_version): logger.warning("ARTIQ version mismatch: current %s < %s minimum", artiq_version, min_artiq_version) diff --git a/versioneer.py b/versioneer.py index 93f1c661d..68574501b 100644 --- a/versioneer.py +++ b/versioneer.py @@ -13,7 +13,7 @@ def get_version(): srcroot = os.path.dirname(os.path.abspath(__file__)) with open(os.path.join(srcroot, "MAJOR_VERSION"), "r") as f: version = f.read().strip() - version += ".unknown" + version += ".0" if os.path.exists(os.path.join(srcroot, "BETA")): version += ".beta" return version From bd95d9cf3d4b9365df58788b3d3460dc8fff5e62 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 19 Nov 2021 19:13:50 +0800 Subject: [PATCH 033/352] coredevice/zotino: port to NAC3 --- artiq/coredevice/ad53xx.py | 112 +++++++++++++++++++++---------------- artiq/coredevice/zotino.py | 20 ++++--- 2 files changed, 76 insertions(+), 56 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 9a2b8eb2e..4d7656072 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -8,17 +8,19 @@ time is an error. # Designed from the data sheets and somewhat after the linux kernel # iio driver. -from numpy import int32 +from numpy import int32, int64 -from artiq.language.core import (kernel, portable, delay_mu, delay, now_mu, - at_mu) +from artiq.language.core import nac3, kernel, portable, KernelInvariant from artiq.language.units import ns, us -from artiq.coredevice import spi2 as spi +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut +from artiq.coredevice.spi2 import * -SPI_AD53XX_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | - 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 1*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + +SPI_AD53XX_CONFIG = (0*SPI_OFFLINE | 1*SPI_END | + 0*SPI_INPUT | 0*SPI_CS_POLARITY | + 0*SPI_CLK_POLARITY | 1*SPI_CLK_PHASE | + 0*SPI_LSB_FIRST | 0*SPI_HALF_DUPLEX) AD53XX_CMD_DATA = 3 << 22 AD53XX_CMD_OFFSET = 2 << 22 @@ -52,7 +54,7 @@ AD53XX_READ_AB3 = 0x109 << 7 @portable -def ad53xx_cmd_write_ch(channel, value, op): +def ad53xx_cmd_write_ch(channel: int32, value: int32, op: int32) -> int32: """Returns the word that must be written to the DAC to set a DAC channel register to a given value. @@ -67,7 +69,7 @@ def ad53xx_cmd_write_ch(channel, value, op): @portable -def ad53xx_cmd_read_ch(channel, op): +def ad53xx_cmd_read_ch(channel: int32, op: int32) -> int32: """Returns the word that must be written to the DAC to read a given DAC channel register. @@ -82,7 +84,7 @@ def ad53xx_cmd_read_ch(channel, op): # maintain function definition for backward compatibility @portable -def voltage_to_mu(voltage, offset_dacs=0x2000, vref=5.): +def voltage_to_mu(voltage: float, offset_dacs: int32 = 0x2000, vref: float = 5.) -> int32: """Returns the 16-bit DAC register value required to produce a given output voltage, assuming offset and gain errors have been trimmed out. @@ -100,22 +102,25 @@ def voltage_to_mu(voltage, offset_dacs=0x2000, vref=5.): :param vref: DAC reference voltage (default: 5.) :return: The 16-bit DAC register value """ - code = int(round((1 << 16) * (voltage / (4. * vref)) + offset_dacs * 0x4)) + code = round(float(1 << 16) * (voltage / (4. * vref))) + offset_dacs * 0x4 if code < 0x0 or code > 0xffff: - raise ValueError("Invalid DAC voltage!") + # NAC3TODO raise ValueError("Invalid DAC voltage!") + pass return code +@nac3 class _DummyTTL: - @portable + @kernel def on(self): pass - @portable + @kernel def off(self): pass +@nac3 class AD53xx: """Analog devices AD53[67][0123] family of multi-channel Digital to Analog Converters. @@ -137,8 +142,15 @@ class AD53xx: experiments. (default: 8192) :param core_device: Core device name (default: "core") """ - kernel_invariants = {"bus", "ldac", "clr", "chip_select", "div_write", - "div_read", "vref", "core"} + core: KernelInvariant[Core] + bus: KernelInvariant[SPIMaster] + ldac: KernelInvariant[TTLOut] + clr: KernelInvariant[TTLOut] + chip_select: KernelInvariant[int32] + div_write: KernelInvariant[int32] + div_read: KernelInvariant[int32] + vref: KernelInvariant[float] + offset_dacs: int32 def __init__(self, dmgr, spi_device, ldac_device=None, clr_device=None, chip_select=1, div_write=4, div_read=16, vref=5., @@ -161,7 +173,7 @@ class AD53xx: self.core = dmgr.get(core) @kernel - def init(self, blind=False): + def init(self, blind: bool = False): """Configures the SPI bus, drives LDAC and CLR high, programmes the offset DACs, and enables overtemperature shutdown. @@ -177,22 +189,25 @@ class AD53xx: self.chip_select) self.write_offset_dacs_mu(self.offset_dacs) if not blind: - ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) + ctrl = self.read_reg(0, AD53XX_READ_CONTROL) if ctrl == 0xffff: - raise ValueError("DAC not found") - if ctrl & 0b10000: - raise ValueError("DAC over temperature") - delay(25*us) + # NAC3TODO raise ValueError("DAC not found") + pass + if (ctrl & 0b10000) != 0: + # NAC3TODO raise ValueError("DAC over temperature") + pass + self.core.delay(125.*us) # NAC3TODO try to restore original 25us after kernel invariants self.bus.write( # enable power and overtemperature shutdown (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_CONTROL | 0b0010) << 8) if not blind: - ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) + ctrl = self.read_reg(0, AD53XX_READ_CONTROL) if (ctrl & 0b10111) != 0b00010: - raise ValueError("DAC CONTROL readback mismatch") - delay(15*us) + # NAC3TODO raise ValueError("DAC CONTROL readback mismatch") + pass + self.core.delay(115.*us) # NAC3TODO try to restore original 15us after kernel invariants @kernel - def read_reg(self, channel=0, op=AD53XX_READ_X1A): + def read_reg(self, channel: int32 = 0, op: int32 = AD53XX_READ_X1A) -> int32: """Read a DAC register. This method advances the timeline by the duration of two SPI transfers @@ -205,17 +220,16 @@ class AD53xx: :return: The 16 bit register value """ self.bus.write(ad53xx_cmd_read_ch(channel, op) << 8) - self.bus.set_config_mu(SPI_AD53XX_CONFIG | spi.SPI_INPUT, 24, + self.bus.set_config_mu(SPI_AD53XX_CONFIG | SPI_INPUT, 24, self.div_read, self.chip_select) - delay(270*ns) # t_21 min sync high in readback + self.core.delay(270.*ns) # t_21 min sync high in readback self.bus.write((AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_NOP) << 8) self.bus.set_config_mu(SPI_AD53XX_CONFIG, 24, self.div_write, self.chip_select) - # FIXME: the int32 should not be needed to resolve unification - return self.bus.read() & int32(0xffff) + return self.bus.read() & 0xffff @kernel - def write_offset_dacs_mu(self, value): + def write_offset_dacs_mu(self, value: int32): """Program the OFS0 and OFS1 offset DAC registers. Writes to the offset DACs take effect immediately without requiring @@ -230,7 +244,7 @@ class AD53xx: self.bus.write((AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_OFS1 | value) << 8) @kernel - def write_gain_mu(self, channel, gain=0xffff): + def write_gain_mu(self, channel: int32, gain: int32 = 0xffff): """Program the gain register for a DAC channel. The DAC output is not updated until LDAC is pulsed (see :meth load:). @@ -242,7 +256,7 @@ class AD53xx: ad53xx_cmd_write_ch(channel, gain, AD53XX_CMD_GAIN) << 8) @kernel - def write_offset_mu(self, channel, offset=0x8000): + def write_offset_mu(self, channel: int32, offset: int32 = 0x8000): """Program the offset register for a DAC channel. The DAC output is not updated until LDAC is pulsed (see :meth load:). @@ -254,7 +268,7 @@ class AD53xx: ad53xx_cmd_write_ch(channel, offset, AD53XX_CMD_OFFSET) << 8) @kernel - def write_offset(self, channel, voltage): + def write_offset(self, channel: int32, voltage: float): """Program the DAC offset voltage for a channel. An offset of +V can be used to trim out a DAC offset error of -V. @@ -267,7 +281,7 @@ class AD53xx: self.vref)) @kernel - def write_dac_mu(self, channel, value): + def write_dac_mu(self, channel: int32, value: int32): """Program the DAC input register for a channel. The DAC output is not updated until LDAC is pulsed (see :meth load:). @@ -277,7 +291,7 @@ class AD53xx: ad53xx_cmd_write_ch(channel, value, AD53XX_CMD_DATA) << 8) @kernel - def write_dac(self, channel, voltage): + def write_dac(self, channel: int32, voltage: float): """Program the DAC output voltage for a channel. The DAC output is not updated until LDAC is pulsed (see :meth load:). @@ -299,11 +313,11 @@ class AD53xx: This method advances the timeline by two RTIO clock periods. """ self.ldac.off() - delay_mu(2*self.bus.ref_period_mu) # t13 = 10ns ldac pulse width low + delay_mu(int64(2)*self.bus.ref_period_mu) # t13 = 10ns ldac pulse width low self.ldac.on() @kernel - def set_dac_mu(self, values, channels=list(range(40))): + def set_dac_mu(self, values: list[int32], channels: list[int32] = list(range(40))): """Program multiple DAC channels and pulse LDAC to update the DAC outputs. @@ -322,17 +336,19 @@ class AD53xx: t0 = now_mu() # t10: max busy period after writing to DAC registers - t_10 = self.core.seconds_to_mu(1500*ns) + t_10 = self.core.seconds_to_mu(1500.*ns) + # NAC3TODO len(values) https://git.m-labs.hk/M-Labs/nac3/issues/103 + len_values = 4 # compensate all delays that will be applied - delay_mu(-t_10-len(values)*self.bus.xfer_duration_mu) - for i in range(len(values)): + delay_mu(-t_10-int64(len_values)*self.bus.xfer_duration_mu) + for i in range(len_values): self.write_dac_mu(channels[i], values[i]) delay_mu(t_10) self.load() at_mu(t0) @kernel - def set_dac(self, voltages, channels=list(range(40))): + def set_dac(self, voltages: list[float], channels: list[int32] = list(range(40))): """Program multiple DAC channels and pulse LDAC to update the DAC outputs. @@ -351,8 +367,8 @@ class AD53xx: self.set_dac_mu(values, channels) @kernel - def calibrate(self, channel, vzs, vfs): - """ Two-point calibration of a DAC channel. + def calibrate(self, channel: int32, vzs: float, vfs: float): + """Two-point calibration of a DAC channel. Programs the offset and gain register to trim out DAC errors. Does not take effect until LDAC is pulsed (see :meth load:). @@ -371,15 +387,15 @@ class AD53xx: gain_err = voltage_to_mu(vfs, self.offset_dacs, self.vref) - ( offset_err + 0xffff) - assert offset_err <= 0 - assert gain_err >= 0 + # NAC3TODO assert offset_err <= 0 + # NAC3TODO assert gain_err >= 0 self.core.break_realtime() self.write_offset_mu(channel, 0x8000-offset_err) self.write_gain_mu(channel, 0xffff-gain_err) @portable - def voltage_to_mu(self, voltage): + def voltage_to_mu(self, voltage: float) -> int32: """Returns the 16-bit DAC register value required to produce a given output voltage, assuming offset and gain errors have been trimmed out. diff --git a/artiq/coredevice/zotino.py b/artiq/coredevice/zotino.py index 9052f589a..a6c6a3703 100644 --- a/artiq/coredevice/zotino.py +++ b/artiq/coredevice/zotino.py @@ -4,19 +4,23 @@ Output event replacement is not supported and issuing commands at the same time is an error. """ -from artiq.language.core import kernel -from artiq.coredevice import spi2 as spi +from numpy import int32 + +from artiq.language.core import nac3, kernel +from artiq.coredevice.spi2 import * from artiq.coredevice.ad53xx import SPI_AD53XX_CONFIG, AD53xx -_SPI_SR_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | - 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + +_SPI_SR_CONFIG = (0*SPI_OFFLINE | 1*SPI_END | + 0*SPI_INPUT | 0*SPI_CS_POLARITY | + 0*SPI_CLK_POLARITY | 0*SPI_CLK_PHASE | + 0*SPI_LSB_FIRST | 0*SPI_HALF_DUPLEX) _SPI_CS_DAC = 1 _SPI_CS_SR = 2 +@nac3 class Zotino(AD53xx): """ Zotino 32-channel, 16-bit 1MSPS DAC. @@ -42,8 +46,8 @@ class Zotino(AD53xx): div_read=div_read, core=core) @kernel - def set_leds(self, leds): - """ Sets the states of the 8 user LEDs. + def set_leds(self, leds: int32): + """Sets the states of the 8 user LEDs. :param leds: 8-bit word with LED state """ From 34789767f0f360f25caa6f44cd7058ad0d94af25 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 22 Nov 2021 18:23:28 +0800 Subject: [PATCH 034/352] firmware: fix compilation 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 cbc767119dd4fd668e0b76e1f5f873e872dc16e2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Nov 2021 15:21:56 +0800 Subject: [PATCH 035/352] flake: update dependencies --- flake.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/flake.lock b/flake.lock index c99b82aa7..0676dbb48 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1636992969, - "narHash": "sha256-N1DBtHSrN2usDeDYD6IcnAUcMfc+i+UKv0U/+j7n5HY=", + "lastModified": 1637337116, + "narHash": "sha256-LKqAcdL+woWeYajs02bDQ7q8rsqgXuzhC354NoRaV80=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "4c8fc3d7b625d2d34bfb5aedf03c131aef2f87f8", + "rev": "cbc7435f5b0b3d17b16fb1d20cf7b616eec5e093", "type": "github" }, "original": { @@ -18,16 +18,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1636698608, - "narHash": "sha256-sxLLeQmH3UrP3UANqXzMLE0bPDgY5aIt04iBoPffG2E=", + "lastModified": 1637636156, + "narHash": "sha256-E2ym4Vcpqu9JYoQDXJZR48gVD+LPPbaCoYveIk7Xu3Y=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "92c881b6a72abce5bb2f5db3f903b4871d13aaa9", + "rev": "b026e1cf87a108dd06fe521f224fdc72fd0b013d", "type": "github" }, "original": { "owner": "NixOS", - "ref": "master", + "ref": "release-21.11", "repo": "nixpkgs", "type": "github" } @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1637055460, - "narHash": "sha256-XMPoYABsiakMoQnFgBSRkFkSAS8TFZDxfDrpGfdKL9k=", + "lastModified": 1637637728, + "narHash": "sha256-HJwcZo1cvLPYyuWatXTIn8TIzf9ViqE16a5b+KukHok=", "ref": "master", - "rev": "1e47b364c5ba3a60d7715faae496fe4c24011591", - "revCount": 430, + "rev": "970f075490aa71404d94000f934a85b3008e4087", + "revCount": 442, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From d8e1a22bdf5fc99f20dc2381f2ecd2e6e4fdc41d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Nov 2021 16:12:36 +0800 Subject: [PATCH 036/352] coredevice/ad53xx: remove problematic default param --- artiq/coredevice/ad53xx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 4d7656072..0266ab836 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -317,7 +317,7 @@ class AD53xx: self.ldac.on() @kernel - def set_dac_mu(self, values: list[int32], channels: list[int32] = list(range(40))): + def set_dac_mu(self, values: list[int32], channels: list[int32]): # NAC3TODO default list(range(40)) """Program multiple DAC channels and pulse LDAC to update the DAC outputs. @@ -348,7 +348,7 @@ class AD53xx: at_mu(t0) @kernel - def set_dac(self, voltages: list[float], channels: list[int32] = list(range(40))): + def set_dac(self, voltages: list[float], channels: list[int32]): # NAC3TODO default list(range(40)) """Program multiple DAC channels and pulse LDAC to update the DAC outputs. From 3a6fcd069dec9037595050f7909e80d6fa56293f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Nov 2021 16:37:40 +0800 Subject: [PATCH 037/352] remove old examples --- artiq/examples/kasli/device_db.py | 231 ------------------ artiq/examples/kasli/idle_kernel.py | 21 -- .../kasli_drtioswitching/device_db.py | 34 --- .../kasli_drtioswitching/repository/blink.py | 16 -- artiq/examples/kasli_sawgmaster/device_db.py | 177 -------------- .../kasli_sawgmaster/repository/basemod.py | 25 -- .../repository/sines_2sayma.py | 37 --- .../repository/sines_urukul_sayma.py | 89 ------- artiq/examples/metlino_sayma_ttl/device_db.py | 95 ------- .../metlino_sayma_ttl/repository/demo.py | 129 ---------- artiq/examples/sayma_master/device_db.py | 166 ------------- .../examples/sayma_master/repository/demo.py | 41 ---- 12 files changed, 1061 deletions(-) delete mode 100644 artiq/examples/kasli/device_db.py delete mode 100644 artiq/examples/kasli/idle_kernel.py delete mode 100644 artiq/examples/kasli_drtioswitching/device_db.py delete mode 100644 artiq/examples/kasli_drtioswitching/repository/blink.py delete mode 100644 artiq/examples/kasli_sawgmaster/device_db.py delete mode 100644 artiq/examples/kasli_sawgmaster/repository/basemod.py delete mode 100644 artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py delete mode 100644 artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py delete mode 100644 artiq/examples/metlino_sayma_ttl/device_db.py delete mode 100644 artiq/examples/metlino_sayma_ttl/repository/demo.py delete mode 100644 artiq/examples/sayma_master/device_db.py delete mode 100644 artiq/examples/sayma_master/repository/demo.py diff --git a/artiq/examples/kasli/device_db.py b/artiq/examples/kasli/device_db.py deleted file mode 100644 index 4b20c7a28..000000000 --- a/artiq/examples/kasli/device_db.py +++ /dev/null @@ -1,231 +0,0 @@ -# Tester device database - -core_addr = "192.168.1.70" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - - -# DIO (EEM5) starting at RTIO channel 0 -for i in range(8): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": i}, - } - device_db["ttl{}_counter".format(i)] = { - "type": "local", - "module": "artiq.coredevice.edge_counter", - "class": "EdgeCounter", - "arguments": {"channel": 8 + i}, - } - - -# Urukul (EEM1) starting at RTIO channel 12 -device_db.update( - eeprom_urukul0={ - "type": "local", - "module": "artiq.coredevice.kasli_i2c", - "class": "KasliEEPROM", - "arguments": {"port": "EEM1"} - }, - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 12} - }, - ttl_urukul0_sync={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLClockGen", - "arguments": {"channel": 13, "acc_width": 4} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 14} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 15} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 16} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 17} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 18} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "sync_device": "ttl_urukul0_sync", - "refclk": 125e6, - "clk_sel": 2 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i), - "sync_delay_seed": "eeprom_urukul0:" + str(64 + 4*i), - "io_update_delay": "eeprom_urukul0:" + str(64 + 4*i), - } - } - - -# Sampler (EEM3) starting at RTIO channel 19 -device_db["spi_sampler0_adc"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 19} -} -device_db["spi_sampler0_pgia"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 20} -} -device_db["spi_sampler0_cnv"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 21}, -} -device_db["sampler0"] = { - "type": "local", - "module": "artiq.coredevice.sampler", - "class": "Sampler", - "arguments": { - "spi_adc_device": "spi_sampler0_adc", - "spi_pgia_device": "spi_sampler0_pgia", - "cnv_device": "spi_sampler0_cnv" - } -} - - -# Zotino (EEM4) starting at RTIO channel 22 -device_db["spi_zotino0"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 22} -} -device_db["ttl_zotino0_ldac"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 23} -} -device_db["ttl_zotino0_clr"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 24} -} -device_db["zotino0"] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino0", - "ldac_device": "ttl_zotino0_ldac", - "clr_device": "ttl_zotino0_clr" - } -} - - -device_db.update( - led0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 25} - }, - led1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 26} - }, -) - -device_db.update( - i2c_switch="i2c_switch0", - - ttl_out="ttl4", - ttl_out_serdes="ttl4", - - loop_out="ttl4", - loop_in="ttl0", - loop_in_counter="ttl0_counter", - - # Urukul CPLD with sync and io_update, IFC MODE 0b1000 - urukul_cpld="urukul0_cpld", - # Urukul AD9910 with switch TTL, internal 125 MHz MMCX connection - urukul_ad9910="urukul0_ch0", -) diff --git a/artiq/examples/kasli/idle_kernel.py b/artiq/examples/kasli/idle_kernel.py deleted file mode 100644 index 05184f731..000000000 --- a/artiq/examples/kasli/idle_kernel.py +++ /dev/null @@ -1,21 +0,0 @@ -from artiq.experiment import * - - -class IdleKernel(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("led0") - - @kernel - def run(self): - start_time = now_mu() + self.core.seconds_to_mu(500*ms) - while self.core.get_rtio_counter_mu() < start_time: - pass - self.core.reset() - while True: - self.led0.pulse(250*ms) - delay(125*ms) - self.led0.pulse(125*ms) - delay(125*ms) - self.led0.pulse(125*ms) - delay(250*ms) diff --git a/artiq/examples/kasli_drtioswitching/device_db.py b/artiq/examples/kasli_drtioswitching/device_db.py deleted file mode 100644 index 433eaf7bc..000000000 --- a/artiq/examples/kasli_drtioswitching/device_db.py +++ /dev/null @@ -1,34 +0,0 @@ -core_addr = "192.168.1.70" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, -} - -for i in range(3): - device_db["led" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": i << 16}, - } diff --git a/artiq/examples/kasli_drtioswitching/repository/blink.py b/artiq/examples/kasli_drtioswitching/repository/blink.py deleted file mode 100644 index 2af2d1233..000000000 --- a/artiq/examples/kasli_drtioswitching/repository/blink.py +++ /dev/null @@ -1,16 +0,0 @@ -from artiq.experiment import * - - -class Blink(EnvExperiment): - def build(self): - self.setattr_device("core") - self.leds = [self.get_device("led0"), self.get_device("led2")] - - @kernel - def run(self): - self.core.reset() - - while True: - for led in self.leds: - led.pulse(200*ms) - delay(200*ms) diff --git a/artiq/examples/kasli_sawgmaster/device_db.py b/artiq/examples/kasli_sawgmaster/device_db.py deleted file mode 100644 index 4cba2bbd2..000000000 --- a/artiq/examples/kasli_sawgmaster/device_db.py +++ /dev/null @@ -1,177 +0,0 @@ -core_addr = "192.168.1.70" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, -} - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 0} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 1} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 2} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 3} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 4} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 5} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 150e6, - "clk_sel": 2 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 16, # 600MHz sample rate - "pll_vco": 2, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - -""" -artiq_route routing.bin init -artiq_route routing.bin set 0 0 -artiq_route routing.bin set 1 1 0 -artiq_route routing.bin set 2 1 1 0 -artiq_route routing.bin set 3 2 0 -artiq_route routing.bin set 4 2 1 0 -artiq_coremgmt -D kasli config write -f routing_table routing.bin -""" - -for sayma in range(2): - amc_base = 0x010000 + sayma*0x020000 - rtm_base = 0x020000 + sayma*0x020000 - for i in range(4): - device_db["led" + str(4*sayma+i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + i} - } - for i in range(2): - device_db["ttl_mcx" + str(2*sayma+i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut", - "arguments": {"channel": amc_base + 4 + i} - } - for i in range(8): - device_db["sawg" + str(8*sayma+i)] = { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": amc_base + 6 + i*10, "parallelism": 4} - } - for basemod in range(2): - for i in range(4): - device_db["sawg_sw" + str(8*sayma+4*basemod+i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": rtm_base + basemod*9 + i} - } - att_idx = 2*sayma + basemod - device_db["basemod_att_rst_n"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": rtm_base + basemod*9 + 4} - } - device_db["basemod_att_clk"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": rtm_base + basemod*9 + 5} - } - device_db["basemod_att_le"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": rtm_base + basemod*9 + 6} - } - device_db["basemod_att_mosi"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": rtm_base + basemod*9 + 7} - } - device_db["basemod_att_miso"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut", - "arguments": {"channel": rtm_base + basemod*9 + 8} - } - device_db["basemod_att"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.basemod_att", - "class": "BaseModAtt", - "arguments": { - "rst_n": "basemod_att_rst_n"+str(att_idx), - "clk": "basemod_att_clk"+str(att_idx), - "le": "basemod_att_le"+str(att_idx), - "mosi": "basemod_att_mosi"+str(att_idx), - "miso": "basemod_att_miso"+str(att_idx), - } - } - diff --git a/artiq/examples/kasli_sawgmaster/repository/basemod.py b/artiq/examples/kasli_sawgmaster/repository/basemod.py deleted file mode 100644 index 3ca9a1c86..000000000 --- a/artiq/examples/kasli_sawgmaster/repository/basemod.py +++ /dev/null @@ -1,25 +0,0 @@ -from artiq.experiment import * - - -class BaseMod(EnvExperiment): - def build(self): - self.setattr_device("core") - self.basemods = [self.get_device("basemod_att0"), self.get_device("basemod_att1")] - self.rfsws = [self.get_device("sawg_sw"+str(i)) for i in range(8)] - - @kernel - def run(self): - self.core.reset() - for basemod in self.basemods: - self.core.break_realtime() - delay(10*ms) - basemod.reset() - delay(10*ms) - basemod.set(0.0, 0.0, 0.0, 0.0) - delay(10*ms) - print(basemod.get_mu()) - - self.core.break_realtime() - for rfsw in self.rfsws: - rfsw.on() - delay(1*ms) diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py deleted file mode 100644 index 3a8204941..000000000 --- a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py +++ /dev/null @@ -1,37 +0,0 @@ -from artiq.experiment import * - - -class Sines2Sayma(EnvExperiment): - def build(self): - self.setattr_device("core") - self.sawgs = [self.get_device("sawg"+str(i)) for i in range(16)] - - @kernel - def drtio_is_up(self): - for i in range(5): - if not self.core.get_rtio_destination_status(i): - return False - return True - - @kernel - def run(self): - while True: - print("waiting for DRTIO ready...") - while not self.drtio_is_up(): - pass - print("OK") - - self.core.reset() - - for sawg in self.sawgs: - delay(1*ms) - sawg.reset() - - for sawg in self.sawgs: - delay(1*ms) - sawg.amplitude1.set(.4) - # Do not use a sub-multiple of oscilloscope sample rates. - sawg.frequency0.set(9*MHz) - - while self.drtio_is_up(): - pass diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py deleted file mode 100644 index dfd8e46c9..000000000 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ /dev/null @@ -1,89 +0,0 @@ -from artiq.experiment import * - - -class SinesUrukulSayma(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("urukul0_cpld") - - # Urukul clock output syntonized to the RTIO clock. - # Can be used as HMC830 reference on Sayma RTM. - # When using this reference, Sayma must be recalibrated every time Urukul - # is rebooted, as Urukul is not synchronized to the Kasli. - self.urukul_hmc_ref = self.get_device("urukul0_ch3") - - # Urukul measurement channels - compare with SAWG outputs. - # When testing sync, do not reboot Urukul, as it is not - # synchronized to the Kasli. - self.urukul_meas = [self.get_device("urukul0_ch" + str(i)) for i in range(3)] - # The same waveform is output on all first 4 SAWG channels (first DAC). - self.sawgs = [self.get_device("sawg"+str(i)) for i in range(4)] - self.basemod = self.get_device("basemod_att0") - self.rfsws = [self.get_device("sawg_sw"+str(i)) for i in range(4)] - - - # DRTIO destinations: - # 0: local - # 1: Sayma AMC - # 2: Sayma RTM - @kernel - def drtio_is_up(self): - for i in range(3): - if not self.core.get_rtio_destination_status(i): - return False - return True - - @kernel - def run(self): - f = 9*MHz - dds_ftw = self.urukul_meas[0].frequency_to_ftw(f) - sawg_ftw = self.sawgs[0].frequency0.to_mu(f) - if dds_ftw != sawg_ftw: - print("DDS and SAWG FTWs do not match:", dds_ftw, sawg_ftw) - return - - self.core.reset() - self.urukul0_cpld.init() - - delay(1*ms) - self.urukul_hmc_ref.init() - self.urukul_hmc_ref.set_mu(0x40000000, asf=self.urukul_hmc_ref.amplitude_to_asf(0.6)) - self.urukul_hmc_ref.set_att(6.) - self.urukul_hmc_ref.sw.on() - - for urukul_ch in self.urukul_meas: - delay(1*ms) - urukul_ch.init() - urukul_ch.set_mu(dds_ftw, asf=urukul_ch.amplitude_to_asf(0.5)) - urukul_ch.set_att(6.) - urukul_ch.sw.on() - - while True: - print("waiting for DRTIO ready...") - while not self.drtio_is_up(): - pass - print("OK") - - self.core.reset() - - delay(10*ms) - self.basemod.reset() - delay(10*ms) - self.basemod.set(3.0, 3.0, 3.0, 3.0) - delay(10*ms) - for rfsw in self.rfsws: - delay(1*ms) - rfsw.on() - - for sawg in self.sawgs: - delay(1*ms) - sawg.reset() - - for sawg in self.sawgs: - delay(1*ms) - sawg.amplitude1.set(.4) - sawg.frequency0.set_mu(sawg_ftw) - sawg.phase0.set_mu(sawg_ftw*now_mu() >> 17) - - while self.drtio_is_up(): - pass diff --git a/artiq/examples/metlino_sayma_ttl/device_db.py b/artiq/examples/metlino_sayma_ttl/device_db.py deleted file mode 100644 index c8c3acb8e..000000000 --- a/artiq/examples/metlino_sayma_ttl/device_db.py +++ /dev/null @@ -1,95 +0,0 @@ -core_addr = "192.168.1.65" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - } -} - -# master peripherals -for i in range(4): - device_db["led" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": i}, -} - -# DEST#1 peripherals -amc_base = 0x070000 -rtm_base = 0x020000 - -for i in range(4): - device_db["led" + str(4+i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + i}, - } - -#DIO (EEM0) starting at RTIO channel 0x000056 -for i in range(8): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + 0x000056 + i}, - } - -#DIO (EEM1) starting at RTIO channel 0x00005e -for i in range(8): - device_db["ttl" + str(8+i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + 0x00005e + i}, - } - -device_db["fmcdio_dirctl_clk"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + 0x000066} -} - -device_db["fmcdio_dirctl_ser"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + 0x000067} -} - -device_db["fmcdio_dirctl_latch"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + 0x000068} -} - -device_db["fmcdio_dirctl"] = { - "type": "local", - "module": "artiq.coredevice.shiftreg", - "class": "ShiftReg", - "arguments": {"clk": "fmcdio_dirctl_clk", - "ser": "fmcdio_dirctl_ser", - "latch": "fmcdio_dirctl_latch"} -} diff --git a/artiq/examples/metlino_sayma_ttl/repository/demo.py b/artiq/examples/metlino_sayma_ttl/repository/demo.py deleted file mode 100644 index bb273ce2c..000000000 --- a/artiq/examples/metlino_sayma_ttl/repository/demo.py +++ /dev/null @@ -1,129 +0,0 @@ -import sys -import os -import select - -from artiq.experiment import * -from artiq.coredevice.fmcdio_vhdci_eem import * - - -def chunker(seq, size): - res = [] - for el in seq: - res.append(el) - if len(res) == size: - yield res - res = [] - if res: - yield res - - -def is_enter_pressed() -> TBool: - if os.name == "nt": - if msvcrt.kbhit() and msvcrt.getch() == b"\r": - return True - else: - return False - else: - if select.select([sys.stdin, ], [], [], 0.0)[0]: - sys.stdin.read(1) - return True - else: - return False - - -class Demo(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("fmcdio_dirctl") - - self.leds = dict() - self.ttl_outs = dict() - - ddb = self.get_device_db() - for name, desc in ddb.items(): - if isinstance(desc, dict) and desc["type"] == "local": - module, cls = desc["module"], desc["class"] - if (module, cls) == ("artiq.coredevice.ttl", "TTLOut"): - dev = self.get_device(name) - if "led" in name: # guess - self.leds[name] = dev - elif "ttl" in name: # to exclude fmcdio_dirctl - self.ttl_outs[name] = dev - - self.leds = sorted(self.leds.items(), key=lambda x: x[1].channel) - self.ttl_outs = sorted(self.ttl_outs.items(), key=lambda x: x[1].channel) - - self.dirctl_word = ( - shiftreg_bits(0, dio_bank0_out_pins | dio_bank1_out_pins) | - shiftreg_bits(1, dio_bank0_out_pins | dio_bank1_out_pins) - ) - - @kernel - def init(self): - self.core.break_realtime() - print("*** Waiting for DRTIO ready...") - drtio_indices = [7] - for i in drtio_indices: - while not self.drtio_is_up(i): - pass - - self.fmcdio_dirctl.set(self.dirctl_word) - - @kernel - def drtio_is_up(self, drtio_index): - if not self.core.get_rtio_destination_status(drtio_index): - return False - print("DRTIO #", drtio_index, "is ready\n") - return True - - @kernel - def test_led(self, led): - while not is_enter_pressed(): - self.core.break_realtime() - # do not fill the FIFOs too much to avoid long response times - t = now_mu() - self.core.seconds_to_mu(0.2) - while self.core.get_rtio_counter_mu() < t: - pass - for i in range(3): - led.pulse(100*ms) - delay(100*ms) - - def test_leds(self): - print("*** Testing LEDs.") - print("Check for blinking. Press ENTER when done.") - - for led_name, led_dev in self.leds: - print("Testing LED: {}".format(led_name)) - self.test_led(led_dev) - - @kernel - def test_ttl_out_chunk(self, ttl_chunk): - while not is_enter_pressed(): - self.core.break_realtime() - for _ in range(50000): - i = 0 - for ttl in ttl_chunk: - i += 1 - for _ in range(i): - ttl.pulse(1*us) - delay(1*us) - delay(10*us) - - def test_ttl_outs(self): - print("*** Testing TTL outputs.") - print("Outputs are tested in groups of 4. Touch each TTL connector") - print("with the oscilloscope probe tip, and check that the number of") - print("pulses corresponds to its number in the group.") - print("Press ENTER when done.") - - for ttl_chunk in chunker(self.ttl_outs, 4): - print("Testing TTL outputs: {}.".format(", ".join(name for name, dev in ttl_chunk))) - self.test_ttl_out_chunk([dev for name, dev in ttl_chunk]) - - def run(self): - self.core.reset() - - if self.leds: - self.test_leds() - if self.ttl_outs: - self.test_ttl_outs() diff --git a/artiq/examples/sayma_master/device_db.py b/artiq/examples/sayma_master/device_db.py deleted file mode 100644 index 51eede704..000000000 --- a/artiq/examples/sayma_master/device_db.py +++ /dev/null @@ -1,166 +0,0 @@ -core_addr = "192.168.1.60" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, -} - -for i in range(4): - device_db["led" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": i}, - } - - -for i in range(2): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut", - "arguments": {"channel": 4 + i}, - } - - -device_db.update( - fmcdio_dirctl_clk={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 6} - }, - fmcdio_dirctl_ser={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 7} - }, - fmcdio_dirctl_latch={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 8} - }, - fmcdio_dirctl={ - "type": "local", - "module": "artiq.coredevice.shiftreg", - "class": "ShiftReg", - "arguments": {"clk": "fmcdio_dirctl_clk", - "ser": "fmcdio_dirctl_ser", - "latch": "fmcdio_dirctl_latch"} - } -) - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 17} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 18} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 19} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 20} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 21} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 22} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - - -device_db["spi_zotino0"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 23} -} -device_db["ttl_zotino0_ldac"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 24} -} -device_db["ttl_zotino0_clr"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 25} -} -device_db["zotino0"] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino0", - "ldac_device": "ttl_zotino0_ldac", - "clr_device": "ttl_zotino0_clr" - } -} diff --git a/artiq/examples/sayma_master/repository/demo.py b/artiq/examples/sayma_master/repository/demo.py deleted file mode 100644 index 9b40f4b42..000000000 --- a/artiq/examples/sayma_master/repository/demo.py +++ /dev/null @@ -1,41 +0,0 @@ -from artiq.experiment import * -from artiq.coredevice.fmcdio_vhdci_eem import * - - -class Demo(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("fmcdio_dirctl") - - self.ttls = [self.get_device("ttl" + str(i)) for i in range(8)] - self.setattr_device("urukul0_cpld") - self.urukul_chs = [self.get_device("urukul0_ch" + str(i)) for i in range(4)] - self.setattr_device("zotino0") - - self.dirctl_word = ( - shiftreg_bits(1, urukul_out_pins) | - shiftreg_bits(0, urukul_aux_out_pins) | - shiftreg_bits(2, dio_bank0_out_pins | dio_bank1_out_pins) | - shiftreg_bits(3, zotino_out_pins)) - - @kernel - def run(self): - self.core.reset() - delay(10*ms) - self.fmcdio_dirctl.set(self.dirctl_word) - delay(10*ms) - - self.urukul0_cpld.init() - delay(10*ms) - - self.zotino0.init() - delay(1*ms) - for i in range(32): - self.zotino0.write_dac(i, i/4) - delay(1*ms) - - while True: - for ttl in self.ttls: - ttl.pulse(100*ms) - for urukul_ch in self.urukul_chs: - urukul_ch.sw.pulse(100*ms) From f5a5b7a22ae734db852f11ebf19516150aedfe04 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Nov 2021 16:41:29 +0800 Subject: [PATCH 038/352] examples: add nac3devices --- artiq/examples/nac3devices/nac3devices.json | 20 +++++++++++ artiq/examples/nac3devices/nac3devices.py | 37 +++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 artiq/examples/nac3devices/nac3devices.json create mode 100644 artiq/examples/nac3devices/nac3devices.py diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json new file mode 100644 index 000000000..bd8d9043a --- /dev/null +++ b/artiq/examples/nac3devices/nac3devices.json @@ -0,0 +1,20 @@ +{ + "target": "kasli", + "min_artiq_version": "8.0", + "variant": "nac3devices", + "hw_rev": "v1.1", + "base": "standalone", + "core_addr": "192.168.1.70", + "peripherals": [ + { + "type": "zotino", + "ports": [0] + }, + { + "type": "urukul", + "dds": "ad9912", + "ports": [2, 3], + "clk_sel": 2 + } + ] +} diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py new file mode 100644 index 000000000..70d8eec6a --- /dev/null +++ b/artiq/examples/nac3devices/nac3devices.py @@ -0,0 +1,37 @@ +from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.zotino import Zotino +from artiq.coredevice.urukul import CPLD +from artiq.coredevice.ad9912 import AD9912 + +@nac3 +class NAC3Devices(EnvExperiment): + core: KernelInvariant[Core] + zotino0: KernelInvariant[Zotino] + urukul0_cpld: KernelInvariant[CPLD] + urukul0_ch0: KernelInvariant[AD9912] + + def build(self): + self.setattr_device("core") + self.setattr_device("zotino0") + self.setattr_device("urukul0_cpld") + self.setattr_device("urukul0_ch0") + + @kernel + def run(self): + self.core.reset() + self.core.delay(1.*ms) + self.zotino0.init(False) + self.zotino0.set_leds(0x15) + self.core.delay(1.*ms) + self.zotino0.set_dac([1.2, -5.3, 3.4, 4.5], [0, 1, 2, 3]) + + self.core.break_realtime() + self.core.delay(1.*ms) + self.urukul0_cpld.init(False) + self.urukul0_ch0.init() + self.urukul0_ch0.sw.on() + for i in range(10): + self.urukul0_ch0.set((10. + float(i))*MHz) + self.urukul0_ch0.set_att(6.) + self.core.delay(500.*ms) From 29f42ccd8a6b74bca36767351e01ccbac1c75d3b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Nov 2021 17:13:43 +0800 Subject: [PATCH 039/352] coredevice/mirny: port to NAC3 --- artiq/coredevice/mirny.py | 60 ++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py index ddcdd1931..364b71298 100644 --- a/artiq/coredevice/mirny.py +++ b/artiq/coredevice/mirny.py @@ -1,23 +1,24 @@ """RTIO driver for Mirny (4 channel GHz PLLs) """ -from artiq.language.core import kernel, delay +from artiq.language.core import nac3, KernelInvariant, kernel from artiq.language.units import us from numpy import int32 -from artiq.coredevice import spi2 as spi +from artiq.coredevice.core import Core +from artiq.coredevice.spi2 import * SPI_CONFIG = ( - 0 * spi.SPI_OFFLINE - | 0 * spi.SPI_END - | 0 * spi.SPI_INPUT - | 1 * spi.SPI_CS_POLARITY - | 0 * spi.SPI_CLK_POLARITY - | 0 * spi.SPI_CLK_PHASE - | 0 * spi.SPI_LSB_FIRST - | 0 * spi.SPI_HALF_DUPLEX + 0 * SPI_OFFLINE + | 0 * SPI_END + | 0 * SPI_INPUT + | 1 * SPI_CS_POLARITY + | 0 * SPI_CLK_POLARITY + | 0 * SPI_CLK_PHASE + | 0 * SPI_LSB_FIRST + | 0 * SPI_HALF_DUPLEX ) # SPI clock write and read dividers @@ -32,6 +33,7 @@ WE = 1 << 24 PROTO_REV_MATCH = 0x0 +@nac3 class Mirny: """ Mirny PLL-based RF generator. @@ -46,8 +48,12 @@ class Mirny: The effect depends on the hardware revision. :param core_device: Core device name (default: "core") """ - - kernel_invariants = {"bus", "core", "refclk", "clk_sel_hw_rev"} + core: KernelInvariant[Core] + bus: KernelInvariant[SPIMaster] + refclk: KernelInvariant[float] + clk_sel_hw_rev: list[int32] + hw_rev: int32 + clk_sel: int32 def __init__(self, dmgr, spi_device, refclk=100e6, clk_sel="XO", core_device="core"): self.core = dmgr.get(core_device) @@ -81,22 +87,22 @@ class Mirny: # TODO: support clk_div on v1.0 boards @kernel - def read_reg(self, addr): + def read_reg(self, addr: int32) -> int32: """Read a register""" self.bus.set_config_mu( - SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 24, SPIT_RD, SPI_CS + SPI_CONFIG | SPI_INPUT | SPI_END, 24, SPIT_RD, SPI_CS ) self.bus.write((addr << 25)) - return self.bus.read() & int32(0xFFFF) + return self.bus.read() & 0xFFFF @kernel - def write_reg(self, addr, data): + def write_reg(self, addr: int32, data: int32): """Write a register""" - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24, SPIT_WR, SPI_CS) + self.bus.set_config_mu(SPI_CONFIG | SPI_END, 24, SPIT_WR, SPI_CS) self.bus.write((addr << 25) | WE | ((data & 0xFFFF) << 8)) @kernel - def init(self, blind=False): + def init(self, blind: bool = False): """ Initialize and detect Mirny. @@ -110,33 +116,35 @@ class Mirny: if not blind: if (reg0 >> 2) & 0x3 != PROTO_REV_MATCH: - raise ValueError("Mirny PROTO_REV mismatch") - delay(100 * us) # slack + # NAC3TODO raise ValueError("Mirny PROTO_REV mismatch") + pass + self.core.delay(100. * us) # slack # select clock source self.clk_sel = self.clk_sel_hw_rev[self.hw_rev] if self.clk_sel < 0: - raise ValueError("Hardware revision not supported") + # NAC3TODO raise ValueError("Hardware revision not supported") + pass self.write_reg(1, (self.clk_sel << 4)) - delay(1000 * us) + self.core.delay(1000. * us) @kernel - def set_att_mu(self, channel, att): + def set_att_mu(self, channel: int32, att: int32): """Set digital step attenuator in machine units. :param att: Attenuation setting, 8 bit digital. """ - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 16, SPIT_WR, SPI_CS) + self.bus.set_config_mu(SPI_CONFIG | SPI_END, 16, SPIT_WR, SPI_CS) self.bus.write(((channel | 8) << 25) | (att << 16)) @kernel - def write_ext(self, addr, length, data): + def write_ext(self, addr: int32, length: int32, data: int32): """Perform SPI write to a prefixed address""" self.bus.set_config_mu(SPI_CONFIG, 8, SPIT_WR, SPI_CS) self.bus.write(addr << 25) - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, length, SPIT_WR, SPI_CS) + self.bus.set_config_mu(SPI_CONFIG | SPI_END, length, SPIT_WR, SPI_CS) if length < 32: data <<= 32 - length self.bus.write(data) From 580049642519daf6c75be00459a7a915e2eacff9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 24 Nov 2021 16:54:58 +0800 Subject: [PATCH 040/352] coredevice/adf5356_reg: port to NAC3 --- artiq/coredevice/adf5356_reg.py | 299 ++++++++++++++++---------------- 1 file changed, 150 insertions(+), 149 deletions(-) diff --git a/artiq/coredevice/adf5356_reg.py b/artiq/coredevice/adf5356_reg.py index a61582d1a..54b4b839e 100644 --- a/artiq/coredevice/adf5356_reg.py +++ b/artiq/coredevice/adf5356_reg.py @@ -1,642 +1,643 @@ # auto-generated, do not edit -from artiq.language.core import portable -from artiq.language.types import TInt32 from numpy import int32 +from artiq.language.core import portable + + @portable -def ADF5356_REG0_AUTOCAL_GET(reg: TInt32) -> TInt32: +def ADF5356_REG0_AUTOCAL_GET(reg: int32) -> int32: return int32((reg >> 21) & 0x1) @portable -def ADF5356_REG0_AUTOCAL(x: TInt32) -> TInt32: +def ADF5356_REG0_AUTOCAL(x: int32) -> int32: return int32((x & 0x1) << 21) @portable -def ADF5356_REG0_AUTOCAL_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG0_AUTOCAL_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 21)) | ((x & 0x1) << 21)) @portable -def ADF5356_REG0_INT_VALUE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG0_INT_VALUE_GET(reg: int32) -> int32: return int32((reg >> 4) & 0xffff) @portable -def ADF5356_REG0_INT_VALUE(x: TInt32) -> TInt32: +def ADF5356_REG0_INT_VALUE(x: int32) -> int32: return int32((x & 0xffff) << 4) @portable -def ADF5356_REG0_INT_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG0_INT_VALUE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0xffff << 4)) | ((x & 0xffff) << 4)) @portable -def ADF5356_REG0_PRESCALER_GET(reg: TInt32) -> TInt32: +def ADF5356_REG0_PRESCALER_GET(reg: int32) -> int32: return int32((reg >> 20) & 0x1) @portable -def ADF5356_REG0_PRESCALER(x: TInt32) -> TInt32: +def ADF5356_REG0_PRESCALER(x: int32) -> int32: return int32((x & 0x1) << 20) @portable -def ADF5356_REG0_PRESCALER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG0_PRESCALER_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 20)) | ((x & 0x1) << 20)) @portable -def ADF5356_REG1_MAIN_FRAC_VALUE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG1_MAIN_FRAC_VALUE_GET(reg: int32) -> int32: return int32((reg >> 4) & 0xffffff) @portable -def ADF5356_REG1_MAIN_FRAC_VALUE(x: TInt32) -> TInt32: +def ADF5356_REG1_MAIN_FRAC_VALUE(x: int32) -> int32: return int32((x & 0xffffff) << 4) @portable -def ADF5356_REG1_MAIN_FRAC_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG1_MAIN_FRAC_VALUE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0xffffff << 4)) | ((x & 0xffffff) << 4)) @portable -def ADF5356_REG2_AUX_FRAC_LSB_VALUE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG2_AUX_FRAC_LSB_VALUE_GET(reg: int32) -> int32: return int32((reg >> 18) & 0x3fff) @portable -def ADF5356_REG2_AUX_FRAC_LSB_VALUE(x: TInt32) -> TInt32: +def ADF5356_REG2_AUX_FRAC_LSB_VALUE(x: int32) -> int32: return int32((x & 0x3fff) << 18) @portable -def ADF5356_REG2_AUX_FRAC_LSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG2_AUX_FRAC_LSB_VALUE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x3fff << 18)) | ((x & 0x3fff) << 18)) @portable -def ADF5356_REG2_AUX_MOD_LSB_VALUE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG2_AUX_MOD_LSB_VALUE_GET(reg: int32) -> int32: return int32((reg >> 4) & 0x3fff) @portable -def ADF5356_REG2_AUX_MOD_LSB_VALUE(x: TInt32) -> TInt32: +def ADF5356_REG2_AUX_MOD_LSB_VALUE(x: int32) -> int32: return int32((x & 0x3fff) << 4) @portable -def ADF5356_REG2_AUX_MOD_LSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG2_AUX_MOD_LSB_VALUE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x3fff << 4)) | ((x & 0x3fff) << 4)) @portable -def ADF5356_REG3_PHASE_ADJUST_GET(reg: TInt32) -> TInt32: +def ADF5356_REG3_PHASE_ADJUST_GET(reg: int32) -> int32: return int32((reg >> 28) & 0x1) @portable -def ADF5356_REG3_PHASE_ADJUST(x: TInt32) -> TInt32: +def ADF5356_REG3_PHASE_ADJUST(x: int32) -> int32: return int32((x & 0x1) << 28) @portable -def ADF5356_REG3_PHASE_ADJUST_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG3_PHASE_ADJUST_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 28)) | ((x & 0x1) << 28)) @portable -def ADF5356_REG3_PHASE_RESYNC_GET(reg: TInt32) -> TInt32: +def ADF5356_REG3_PHASE_RESYNC_GET(reg: int32) -> int32: return int32((reg >> 29) & 0x1) @portable -def ADF5356_REG3_PHASE_RESYNC(x: TInt32) -> TInt32: +def ADF5356_REG3_PHASE_RESYNC(x: int32) -> int32: return int32((x & 0x1) << 29) @portable -def ADF5356_REG3_PHASE_RESYNC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG3_PHASE_RESYNC_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 29)) | ((x & 0x1) << 29)) @portable -def ADF5356_REG3_PHASE_VALUE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG3_PHASE_VALUE_GET(reg: int32) -> int32: return int32((reg >> 4) & 0xffffff) @portable -def ADF5356_REG3_PHASE_VALUE(x: TInt32) -> TInt32: +def ADF5356_REG3_PHASE_VALUE(x: int32) -> int32: return int32((x & 0xffffff) << 4) @portable -def ADF5356_REG3_PHASE_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG3_PHASE_VALUE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0xffffff << 4)) | ((x & 0xffffff) << 4)) @portable -def ADF5356_REG3_SD_LOAD_RESET_GET(reg: TInt32) -> TInt32: +def ADF5356_REG3_SD_LOAD_RESET_GET(reg: int32) -> int32: return int32((reg >> 30) & 0x1) @portable -def ADF5356_REG3_SD_LOAD_RESET(x: TInt32) -> TInt32: +def ADF5356_REG3_SD_LOAD_RESET(x: int32) -> int32: return int32((x & 0x1) << 30) @portable -def ADF5356_REG3_SD_LOAD_RESET_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG3_SD_LOAD_RESET_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 30)) | ((x & 0x1) << 30)) @portable -def ADF5356_REG4_COUNTER_RESET_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_COUNTER_RESET_GET(reg: int32) -> int32: return int32((reg >> 4) & 0x1) @portable -def ADF5356_REG4_COUNTER_RESET(x: TInt32) -> TInt32: +def ADF5356_REG4_COUNTER_RESET(x: int32) -> int32: return int32((x & 0x1) << 4) @portable -def ADF5356_REG4_COUNTER_RESET_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_COUNTER_RESET_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) @portable -def ADF5356_REG4_CP_THREE_STATE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_CP_THREE_STATE_GET(reg: int32) -> int32: return int32((reg >> 5) & 0x1) @portable -def ADF5356_REG4_CP_THREE_STATE(x: TInt32) -> TInt32: +def ADF5356_REG4_CP_THREE_STATE(x: int32) -> int32: return int32((x & 0x1) << 5) @portable -def ADF5356_REG4_CP_THREE_STATE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_CP_THREE_STATE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 5)) | ((x & 0x1) << 5)) @portable -def ADF5356_REG4_CURRENT_SETTING_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_CURRENT_SETTING_GET(reg: int32) -> int32: return int32((reg >> 10) & 0xf) @portable -def ADF5356_REG4_CURRENT_SETTING(x: TInt32) -> TInt32: +def ADF5356_REG4_CURRENT_SETTING(x: int32) -> int32: return int32((x & 0xf) << 10) @portable -def ADF5356_REG4_CURRENT_SETTING_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_CURRENT_SETTING_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0xf << 10)) | ((x & 0xf) << 10)) @portable -def ADF5356_REG4_DOUBLE_BUFF_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_DOUBLE_BUFF_GET(reg: int32) -> int32: return int32((reg >> 14) & 0x1) @portable -def ADF5356_REG4_DOUBLE_BUFF(x: TInt32) -> TInt32: +def ADF5356_REG4_DOUBLE_BUFF(x: int32) -> int32: return int32((x & 0x1) << 14) @portable -def ADF5356_REG4_DOUBLE_BUFF_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_DOUBLE_BUFF_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 14)) | ((x & 0x1) << 14)) @portable -def ADF5356_REG4_MUX_LOGIC_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_MUX_LOGIC_GET(reg: int32) -> int32: return int32((reg >> 8) & 0x1) @portable -def ADF5356_REG4_MUX_LOGIC(x: TInt32) -> TInt32: +def ADF5356_REG4_MUX_LOGIC(x: int32) -> int32: return int32((x & 0x1) << 8) @portable -def ADF5356_REG4_MUX_LOGIC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_MUX_LOGIC_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 8)) | ((x & 0x1) << 8)) @portable -def ADF5356_REG4_MUXOUT_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_MUXOUT_GET(reg: int32) -> int32: return int32((reg >> 27) & 0x7) @portable -def ADF5356_REG4_MUXOUT(x: TInt32) -> TInt32: +def ADF5356_REG4_MUXOUT(x: int32) -> int32: return int32((x & 0x7) << 27) @portable -def ADF5356_REG4_MUXOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_MUXOUT_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x7 << 27)) | ((x & 0x7) << 27)) @portable -def ADF5356_REG4_PD_POLARITY_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_PD_POLARITY_GET(reg: int32) -> int32: return int32((reg >> 7) & 0x1) @portable -def ADF5356_REG4_PD_POLARITY(x: TInt32) -> TInt32: +def ADF5356_REG4_PD_POLARITY(x: int32) -> int32: return int32((x & 0x1) << 7) @portable -def ADF5356_REG4_PD_POLARITY_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_PD_POLARITY_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 7)) | ((x & 0x1) << 7)) @portable -def ADF5356_REG4_POWER_DOWN_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_POWER_DOWN_GET(reg: int32) -> int32: return int32((reg >> 6) & 0x1) @portable -def ADF5356_REG4_POWER_DOWN(x: TInt32) -> TInt32: +def ADF5356_REG4_POWER_DOWN(x: int32) -> int32: return int32((x & 0x1) << 6) @portable -def ADF5356_REG4_POWER_DOWN_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_POWER_DOWN_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 6)) | ((x & 0x1) << 6)) @portable -def ADF5356_REG4_R_COUNTER_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_R_COUNTER_GET(reg: int32) -> int32: return int32((reg >> 15) & 0x3ff) @portable -def ADF5356_REG4_R_COUNTER(x: TInt32) -> TInt32: +def ADF5356_REG4_R_COUNTER(x: int32) -> int32: return int32((x & 0x3ff) << 15) @portable -def ADF5356_REG4_R_COUNTER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_R_COUNTER_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x3ff << 15)) | ((x & 0x3ff) << 15)) @portable -def ADF5356_REG4_R_DIVIDER_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_R_DIVIDER_GET(reg: int32) -> int32: return int32((reg >> 25) & 0x1) @portable -def ADF5356_REG4_R_DIVIDER(x: TInt32) -> TInt32: +def ADF5356_REG4_R_DIVIDER(x: int32) -> int32: return int32((x & 0x1) << 25) @portable -def ADF5356_REG4_R_DIVIDER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_R_DIVIDER_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 25)) | ((x & 0x1) << 25)) @portable -def ADF5356_REG4_R_DOUBLER_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_R_DOUBLER_GET(reg: int32) -> int32: return int32((reg >> 26) & 0x1) @portable -def ADF5356_REG4_R_DOUBLER(x: TInt32) -> TInt32: +def ADF5356_REG4_R_DOUBLER(x: int32) -> int32: return int32((x & 0x1) << 26) @portable -def ADF5356_REG4_R_DOUBLER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_R_DOUBLER_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 26)) | ((x & 0x1) << 26)) @portable -def ADF5356_REG4_REF_MODE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG4_REF_MODE_GET(reg: int32) -> int32: return int32((reg >> 9) & 0x1) @portable -def ADF5356_REG4_REF_MODE(x: TInt32) -> TInt32: +def ADF5356_REG4_REF_MODE(x: int32) -> int32: return int32((x & 0x1) << 9) @portable -def ADF5356_REG4_REF_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG4_REF_MODE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 9)) | ((x & 0x1) << 9)) @portable -def ADF5356_REG6_BLEED_POLARITY_GET(reg: TInt32) -> TInt32: +def ADF5356_REG6_BLEED_POLARITY_GET(reg: int32) -> int32: return int32((reg >> 31) & 0x1) @portable -def ADF5356_REG6_BLEED_POLARITY(x: TInt32) -> TInt32: +def ADF5356_REG6_BLEED_POLARITY(x: int32) -> int32: return int32((x & 0x1) << 31) @portable -def ADF5356_REG6_BLEED_POLARITY_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG6_BLEED_POLARITY_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 31)) | ((x & 0x1) << 31)) @portable -def ADF5356_REG6_CP_BLEED_CURRENT_GET(reg: TInt32) -> TInt32: +def ADF5356_REG6_CP_BLEED_CURRENT_GET(reg: int32) -> int32: return int32((reg >> 13) & 0xff) @portable -def ADF5356_REG6_CP_BLEED_CURRENT(x: TInt32) -> TInt32: +def ADF5356_REG6_CP_BLEED_CURRENT(x: int32) -> int32: return int32((x & 0xff) << 13) @portable -def ADF5356_REG6_CP_BLEED_CURRENT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG6_CP_BLEED_CURRENT_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0xff << 13)) | ((x & 0xff) << 13)) @portable -def ADF5356_REG6_FB_SELECT_GET(reg: TInt32) -> TInt32: +def ADF5356_REG6_FB_SELECT_GET(reg: int32) -> int32: return int32((reg >> 24) & 0x1) @portable -def ADF5356_REG6_FB_SELECT(x: TInt32) -> TInt32: +def ADF5356_REG6_FB_SELECT(x: int32) -> int32: return int32((x & 0x1) << 24) @portable -def ADF5356_REG6_FB_SELECT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG6_FB_SELECT_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 24)) | ((x & 0x1) << 24)) @portable -def ADF5356_REG6_GATE_BLEED_GET(reg: TInt32) -> TInt32: +def ADF5356_REG6_GATE_BLEED_GET(reg: int32) -> int32: return int32((reg >> 30) & 0x1) @portable -def ADF5356_REG6_GATE_BLEED(x: TInt32) -> TInt32: +def ADF5356_REG6_GATE_BLEED(x: int32) -> int32: return int32((x & 0x1) << 30) @portable -def ADF5356_REG6_GATE_BLEED_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG6_GATE_BLEED_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 30)) | ((x & 0x1) << 30)) @portable -def ADF5356_REG6_MUTE_TILL_LD_GET(reg: TInt32) -> TInt32: +def ADF5356_REG6_MUTE_TILL_LD_GET(reg: int32) -> int32: return int32((reg >> 11) & 0x1) @portable -def ADF5356_REG6_MUTE_TILL_LD(x: TInt32) -> TInt32: +def ADF5356_REG6_MUTE_TILL_LD(x: int32) -> int32: return int32((x & 0x1) << 11) @portable -def ADF5356_REG6_MUTE_TILL_LD_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG6_MUTE_TILL_LD_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 11)) | ((x & 0x1) << 11)) @portable -def ADF5356_REG6_NEGATIVE_BLEED_GET(reg: TInt32) -> TInt32: +def ADF5356_REG6_NEGATIVE_BLEED_GET(reg: int32) -> int32: return int32((reg >> 29) & 0x1) @portable -def ADF5356_REG6_NEGATIVE_BLEED(x: TInt32) -> TInt32: +def ADF5356_REG6_NEGATIVE_BLEED(x: int32) -> int32: return int32((x & 0x1) << 29) @portable -def ADF5356_REG6_NEGATIVE_BLEED_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG6_NEGATIVE_BLEED_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 29)) | ((x & 0x1) << 29)) @portable -def ADF5356_REG6_RF_DIVIDER_SELECT_GET(reg: TInt32) -> TInt32: +def ADF5356_REG6_RF_DIVIDER_SELECT_GET(reg: int32) -> int32: return int32((reg >> 21) & 0x7) @portable -def ADF5356_REG6_RF_DIVIDER_SELECT(x: TInt32) -> TInt32: +def ADF5356_REG6_RF_DIVIDER_SELECT(x: int32) -> int32: return int32((x & 0x7) << 21) @portable -def ADF5356_REG6_RF_DIVIDER_SELECT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG6_RF_DIVIDER_SELECT_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x7 << 21)) | ((x & 0x7) << 21)) @portable -def ADF5356_REG6_RF_OUTPUT_A_ENABLE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG6_RF_OUTPUT_A_ENABLE_GET(reg: int32) -> int32: return int32((reg >> 6) & 0x1) @portable -def ADF5356_REG6_RF_OUTPUT_A_ENABLE(x: TInt32) -> TInt32: +def ADF5356_REG6_RF_OUTPUT_A_ENABLE(x: int32) -> int32: return int32((x & 0x1) << 6) @portable -def ADF5356_REG6_RF_OUTPUT_A_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG6_RF_OUTPUT_A_ENABLE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 6)) | ((x & 0x1) << 6)) @portable -def ADF5356_REG6_RF_OUTPUT_A_POWER_GET(reg: TInt32) -> TInt32: +def ADF5356_REG6_RF_OUTPUT_A_POWER_GET(reg: int32) -> int32: return int32((reg >> 4) & 0x3) @portable -def ADF5356_REG6_RF_OUTPUT_A_POWER(x: TInt32) -> TInt32: +def ADF5356_REG6_RF_OUTPUT_A_POWER(x: int32) -> int32: return int32((x & 0x3) << 4) @portable -def ADF5356_REG6_RF_OUTPUT_A_POWER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG6_RF_OUTPUT_A_POWER_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x3 << 4)) | ((x & 0x3) << 4)) @portable -def ADF5356_REG6_RF_OUTPUT_B_ENABLE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG6_RF_OUTPUT_B_ENABLE_GET(reg: int32) -> int32: return int32((reg >> 10) & 0x1) @portable -def ADF5356_REG6_RF_OUTPUT_B_ENABLE(x: TInt32) -> TInt32: +def ADF5356_REG6_RF_OUTPUT_B_ENABLE(x: int32) -> int32: return int32((x & 0x1) << 10) @portable -def ADF5356_REG6_RF_OUTPUT_B_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG6_RF_OUTPUT_B_ENABLE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 10)) | ((x & 0x1) << 10)) @portable -def ADF5356_REG7_FRAC_N_LD_PRECISION_GET(reg: TInt32) -> TInt32: +def ADF5356_REG7_FRAC_N_LD_PRECISION_GET(reg: int32) -> int32: return int32((reg >> 5) & 0x3) @portable -def ADF5356_REG7_FRAC_N_LD_PRECISION(x: TInt32) -> TInt32: +def ADF5356_REG7_FRAC_N_LD_PRECISION(x: int32) -> int32: return int32((x & 0x3) << 5) @portable -def ADF5356_REG7_FRAC_N_LD_PRECISION_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG7_FRAC_N_LD_PRECISION_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x3 << 5)) | ((x & 0x3) << 5)) @portable -def ADF5356_REG7_LD_CYCLE_COUNT_GET(reg: TInt32) -> TInt32: +def ADF5356_REG7_LD_CYCLE_COUNT_GET(reg: int32) -> int32: return int32((reg >> 8) & 0x3) @portable -def ADF5356_REG7_LD_CYCLE_COUNT(x: TInt32) -> TInt32: +def ADF5356_REG7_LD_CYCLE_COUNT(x: int32) -> int32: return int32((x & 0x3) << 8) @portable -def ADF5356_REG7_LD_CYCLE_COUNT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG7_LD_CYCLE_COUNT_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x3 << 8)) | ((x & 0x3) << 8)) @portable -def ADF5356_REG7_LD_MODE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG7_LD_MODE_GET(reg: int32) -> int32: return int32((reg >> 4) & 0x1) @portable -def ADF5356_REG7_LD_MODE(x: TInt32) -> TInt32: +def ADF5356_REG7_LD_MODE(x: int32) -> int32: return int32((x & 0x1) << 4) @portable -def ADF5356_REG7_LD_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG7_LD_MODE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) @portable -def ADF5356_REG7_LE_SEL_SYNC_EDGE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG7_LE_SEL_SYNC_EDGE_GET(reg: int32) -> int32: return int32((reg >> 27) & 0x1) @portable -def ADF5356_REG7_LE_SEL_SYNC_EDGE(x: TInt32) -> TInt32: +def ADF5356_REG7_LE_SEL_SYNC_EDGE(x: int32) -> int32: return int32((x & 0x1) << 27) @portable -def ADF5356_REG7_LE_SEL_SYNC_EDGE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG7_LE_SEL_SYNC_EDGE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 27)) | ((x & 0x1) << 27)) @portable -def ADF5356_REG7_LE_SYNC_GET(reg: TInt32) -> TInt32: +def ADF5356_REG7_LE_SYNC_GET(reg: int32) -> int32: return int32((reg >> 25) & 0x1) @portable -def ADF5356_REG7_LE_SYNC(x: TInt32) -> TInt32: +def ADF5356_REG7_LE_SYNC(x: int32) -> int32: return int32((x & 0x1) << 25) @portable -def ADF5356_REG7_LE_SYNC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG7_LE_SYNC_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 25)) | ((x & 0x1) << 25)) @portable -def ADF5356_REG7_LOL_MODE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG7_LOL_MODE_GET(reg: int32) -> int32: return int32((reg >> 7) & 0x1) @portable -def ADF5356_REG7_LOL_MODE(x: TInt32) -> TInt32: +def ADF5356_REG7_LOL_MODE(x: int32) -> int32: return int32((x & 0x1) << 7) @portable -def ADF5356_REG7_LOL_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG7_LOL_MODE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 7)) | ((x & 0x1) << 7)) @portable -def ADF5356_REG9_AUTOCAL_TIMEOUT_GET(reg: TInt32) -> TInt32: +def ADF5356_REG9_AUTOCAL_TIMEOUT_GET(reg: int32) -> int32: return int32((reg >> 9) & 0x1f) @portable -def ADF5356_REG9_AUTOCAL_TIMEOUT(x: TInt32) -> TInt32: +def ADF5356_REG9_AUTOCAL_TIMEOUT(x: int32) -> int32: return int32((x & 0x1f) << 9) @portable -def ADF5356_REG9_AUTOCAL_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG9_AUTOCAL_TIMEOUT_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1f << 9)) | ((x & 0x1f) << 9)) @portable -def ADF5356_REG9_SYNTH_LOCK_TIMEOUT_GET(reg: TInt32) -> TInt32: +def ADF5356_REG9_SYNTH_LOCK_TIMEOUT_GET(reg: int32) -> int32: return int32((reg >> 4) & 0x1f) @portable -def ADF5356_REG9_SYNTH_LOCK_TIMEOUT(x: TInt32) -> TInt32: +def ADF5356_REG9_SYNTH_LOCK_TIMEOUT(x: int32) -> int32: return int32((x & 0x1f) << 4) @portable -def ADF5356_REG9_SYNTH_LOCK_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG9_SYNTH_LOCK_TIMEOUT_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1f << 4)) | ((x & 0x1f) << 4)) @portable -def ADF5356_REG9_TIMEOUT_GET(reg: TInt32) -> TInt32: +def ADF5356_REG9_TIMEOUT_GET(reg: int32) -> int32: return int32((reg >> 14) & 0x3ff) @portable -def ADF5356_REG9_TIMEOUT(x: TInt32) -> TInt32: +def ADF5356_REG9_TIMEOUT(x: int32) -> int32: return int32((x & 0x3ff) << 14) @portable -def ADF5356_REG9_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG9_TIMEOUT_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x3ff << 14)) | ((x & 0x3ff) << 14)) @portable -def ADF5356_REG9_VCO_BAND_DIVISION_GET(reg: TInt32) -> TInt32: +def ADF5356_REG9_VCO_BAND_DIVISION_GET(reg: int32) -> int32: return int32((reg >> 24) & 0xff) @portable -def ADF5356_REG9_VCO_BAND_DIVISION(x: TInt32) -> TInt32: +def ADF5356_REG9_VCO_BAND_DIVISION(x: int32) -> int32: return int32((x & 0xff) << 24) @portable -def ADF5356_REG9_VCO_BAND_DIVISION_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG9_VCO_BAND_DIVISION_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0xff << 24)) | ((x & 0xff) << 24)) @portable -def ADF5356_REG10_ADC_CLK_DIV_GET(reg: TInt32) -> TInt32: +def ADF5356_REG10_ADC_CLK_DIV_GET(reg: int32) -> int32: return int32((reg >> 6) & 0xff) @portable -def ADF5356_REG10_ADC_CLK_DIV(x: TInt32) -> TInt32: +def ADF5356_REG10_ADC_CLK_DIV(x: int32) -> int32: return int32((x & 0xff) << 6) @portable -def ADF5356_REG10_ADC_CLK_DIV_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG10_ADC_CLK_DIV_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0xff << 6)) | ((x & 0xff) << 6)) @portable -def ADF5356_REG10_ADC_CONV_GET(reg: TInt32) -> TInt32: +def ADF5356_REG10_ADC_CONV_GET(reg: int32) -> int32: return int32((reg >> 5) & 0x1) @portable -def ADF5356_REG10_ADC_CONV(x: TInt32) -> TInt32: +def ADF5356_REG10_ADC_CONV(x: int32) -> int32: return int32((x & 0x1) << 5) @portable -def ADF5356_REG10_ADC_CONV_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG10_ADC_CONV_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 5)) | ((x & 0x1) << 5)) @portable -def ADF5356_REG10_ADC_ENABLE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG10_ADC_ENABLE_GET(reg: int32) -> int32: return int32((reg >> 4) & 0x1) @portable -def ADF5356_REG10_ADC_ENABLE(x: TInt32) -> TInt32: +def ADF5356_REG10_ADC_ENABLE(x: int32) -> int32: return int32((x & 0x1) << 4) @portable -def ADF5356_REG10_ADC_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG10_ADC_ENABLE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) @portable -def ADF5356_REG11_VCO_BAND_HOLD_GET(reg: TInt32) -> TInt32: +def ADF5356_REG11_VCO_BAND_HOLD_GET(reg: int32) -> int32: return int32((reg >> 24) & 0x1) @portable -def ADF5356_REG11_VCO_BAND_HOLD(x: TInt32) -> TInt32: +def ADF5356_REG11_VCO_BAND_HOLD(x: int32) -> int32: return int32((x & 0x1) << 24) @portable -def ADF5356_REG11_VCO_BAND_HOLD_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG11_VCO_BAND_HOLD_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x1 << 24)) | ((x & 0x1) << 24)) @portable -def ADF5356_REG12_PHASE_RESYNC_CLK_VALUE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG12_PHASE_RESYNC_CLK_VALUE_GET(reg: int32) -> int32: return int32((reg >> 12) & 0xfffff) @portable -def ADF5356_REG12_PHASE_RESYNC_CLK_VALUE(x: TInt32) -> TInt32: +def ADF5356_REG12_PHASE_RESYNC_CLK_VALUE(x: int32) -> int32: return int32((x & 0xfffff) << 12) @portable -def ADF5356_REG12_PHASE_RESYNC_CLK_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG12_PHASE_RESYNC_CLK_VALUE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0xfffff << 12)) | ((x & 0xfffff) << 12)) @portable -def ADF5356_REG13_AUX_FRAC_MSB_VALUE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG13_AUX_FRAC_MSB_VALUE_GET(reg: int32) -> int32: return int32((reg >> 18) & 0x3fff) @portable -def ADF5356_REG13_AUX_FRAC_MSB_VALUE(x: TInt32) -> TInt32: +def ADF5356_REG13_AUX_FRAC_MSB_VALUE(x: int32) -> int32: return int32((x & 0x3fff) << 18) @portable -def ADF5356_REG13_AUX_FRAC_MSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG13_AUX_FRAC_MSB_VALUE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x3fff << 18)) | ((x & 0x3fff) << 18)) @portable -def ADF5356_REG13_AUX_MOD_MSB_VALUE_GET(reg: TInt32) -> TInt32: +def ADF5356_REG13_AUX_MOD_MSB_VALUE_GET(reg: int32) -> int32: return int32((reg >> 4) & 0x3fff) @portable -def ADF5356_REG13_AUX_MOD_MSB_VALUE(x: TInt32) -> TInt32: +def ADF5356_REG13_AUX_MOD_MSB_VALUE(x: int32) -> int32: return int32((x & 0x3fff) << 4) @portable -def ADF5356_REG13_AUX_MOD_MSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: +def ADF5356_REG13_AUX_MOD_MSB_VALUE_UPDATE(reg: int32, x: int32) -> int32: return int32((reg & ~(0x3fff << 4)) | ((x & 0x3fff) << 4)) ADF5356_NUM_REGS = 14 From 519e3d64d87203529b3ec0a3db7066c2c1d593ac Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 28 Nov 2021 12:18:55 +0800 Subject: [PATCH 041/352] flake: update dependencies --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 0676dbb48..c04f9caed 100644 --- a/flake.lock +++ b/flake.lock @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1637637728, - "narHash": "sha256-HJwcZo1cvLPYyuWatXTIn8TIzf9ViqE16a5b+KukHok=", + "lastModified": 1638016066, + "narHash": "sha256-bqpcyTh/CnpBj3rrIJnFgaSjVrgWaPNse68BsJvCGUA=", "ref": "master", - "rev": "970f075490aa71404d94000f934a85b3008e4087", - "revCount": 442, + "rev": "7ee82de3123864dd2429771ccea9d6a4127a0f4d", + "revCount": 445, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From e45c194c49b81758addc2a987776f95489b59165 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 28 Nov 2021 12:38:23 +0800 Subject: [PATCH 042/352] coredevice/adf5356: port to NAC3 --- artiq/coredevice/adf5356.py | 175 ++++++++++++++++++++---------------- 1 file changed, 99 insertions(+), 76 deletions(-) diff --git a/artiq/coredevice/adf5356.py b/artiq/coredevice/adf5356.py index 845067541..e357fefab 100644 --- a/artiq/coredevice/adf5356.py +++ b/artiq/coredevice/adf5356.py @@ -8,25 +8,36 @@ on Mirny-style prefixed SPI buses. # https://www.analog.com/media/en/technical-documentation/data-sheets/ADF5355.pdf # https://www.analog.com/media/en/technical-documentation/user-guides/EV-ADF5355SD1Z-UG-1087.pdf +from numpy import int32, int64 +# NAC3TODO from math import floor, ceil -from artiq.language.core import kernel, portable, delay +from artiq.language.core import nac3, KernelInvariant, kernel, portable, round64 from artiq.language.units import us, GHz, MHz -from artiq.language.types import TInt32, TInt64 -from artiq.coredevice import spi2 as spi +from artiq.coredevice.core import Core +from artiq.coredevice.mirny import Mirny +from artiq.coredevice.ttl import TTLOut +from artiq.coredevice.spi2 import * from artiq.coredevice.adf5356_reg import * -from numpy import int32, int64, floor, ceil +# NAC3TODO +@portable +def floor(x: float) -> int32: + return 0 +@portable +def ceil(x: float) -> int32: + return 0 +# SPI_CONFIG = ( - 0 * spi.SPI_OFFLINE - | 0 * spi.SPI_END - | 0 * spi.SPI_INPUT - | 1 * spi.SPI_CS_POLARITY - | 0 * spi.SPI_CLK_POLARITY - | 0 * spi.SPI_CLK_PHASE - | 0 * spi.SPI_LSB_FIRST - | 0 * spi.SPI_HALF_DUPLEX + 0 * SPI_OFFLINE + | 0 * SPI_END + | 0 * SPI_INPUT + | 1 * SPI_CS_POLARITY + | 0 * SPI_CLK_POLARITY + | 0 * SPI_CLK_PHASE + | 0 * SPI_LSB_FIRST + | 0 * SPI_HALF_DUPLEX ) @@ -38,6 +49,7 @@ ADF5356_MAX_MODULUS2 = int32(1 << 28) # FIXME: ADF5356 has 28 bits MOD2 ADF5356_MAX_R_CNT = int32(1023) +@nac3 class ADF5356: """Analog Devices AD[45]35[56] family of GHz PLLs. @@ -49,7 +61,14 @@ class ADF5356: :param core_device: Core device name (default: "core") """ - kernel_invariants = {"cpld", "sw", "channel", "core", "sysclk"} + core: KernelInvariant[Core] + cpld: KernelInvariant[Mirny] + channel: KernelInvariant[int32] + sw: KernelInvariant[TTLOut] + sysclk: KernelInvariant[float] + regs: list[int32] + ref_doubler: bool + ref_divider: bool def __init__( self, @@ -74,7 +93,7 @@ class ADF5356: self._init_registers() @kernel - def init(self, blind=False): + def init(self, blind: bool = False): """ Initialize and configure the PLL. @@ -84,18 +103,20 @@ class ADF5356: # MUXOUT = VDD self.regs[4] = ADF5356_REG4_MUXOUT_UPDATE(self.regs[4], 1) self.sync() - delay(1000 * us) + self.core.delay(1000. * us) if not self.read_muxout(): - raise ValueError("MUXOUT not high") - delay(800 * us) + # NAC3TODO raise ValueError("MUXOUT not high") + pass + self.core.delay(800. * us) # MUXOUT = DGND self.regs[4] = ADF5356_REG4_MUXOUT_UPDATE(self.regs[4], 2) self.sync() - delay(1000 * us) + self.core.delay(1000. * us) if self.read_muxout(): - raise ValueError("MUXOUT not low") - delay(800 * us) + # NAC3TODO raise ValueError("MUXOUT not low") + pass + self.core.delay(800. * us) # MUXOUT = digital lock-detect self.regs[4] = ADF5356_REG4_MUXOUT_UPDATE(self.regs[4], 6) @@ -103,7 +124,7 @@ class ADF5356: self.sync() @kernel - def set_att_mu(self, att): + def set_att_mu(self, att: int32): """Set digital step attenuator in machine units. :param att: Attenuation setting, 8 bit digital. @@ -111,11 +132,11 @@ class ADF5356: self.cpld.set_att_mu(self.channel, att) @kernel - def write(self, data): + def write(self, data: int32): self.cpld.write_ext(self.channel | 4, 32, data) @kernel - def read_muxout(self): + def read_muxout(self) -> bool: """ Read the state of the MUXOUT line. @@ -124,7 +145,7 @@ class ADF5356: return bool(self.cpld.read_reg(0) & (1 << (self.channel + 8))) @kernel - def set_output_power_mu(self, n): + def set_output_power_mu(self, n: int32): """ Set the power level at output A of the PLL chip in machine units. @@ -132,13 +153,14 @@ class ADF5356: :param n: output power setting, 0, 1, 2, or 3 (see ADF5356 datasheet, fig. 44). """ - if n not in [0, 1, 2, 3]: - raise ValueError("invalid power setting") + if not 0 <= n <= 3: + # NAC3TODO raise ValueError("invalid power setting") + pass self.regs[6] = ADF5356_REG6_RF_OUTPUT_A_POWER_UPDATE(self.regs[6], n) self.sync() @portable - def output_power_mu(self): + def output_power_mu(self) -> int32: """ Return the power level at output A of the PLL chip in machine units. """ @@ -161,25 +183,27 @@ class ADF5356: self.sync() @kernel - def set_frequency(self, f): + def set_frequency(self, f: float): """ Output given frequency on output A. :param f: 53.125 MHz <= f <= 6800 MHz """ - freq = int64(round(f)) + freq = round64(f) if freq > ADF5356_MAX_VCO_FREQ: - raise ValueError("Requested too high frequency") + # NAC3TODO raise ValueError("Requested too high frequency") + pass # select minimal output divider rf_div_sel = 0 while freq < ADF5356_MIN_VCO_FREQ: - freq <<= 1 + freq <<= int64(1) rf_div_sel += 1 if (1 << rf_div_sel) > 64: - raise ValueError("Requested too low frequency") + # NAC3TODO raise ValueError("Requested too low frequency") + pass # choose reference divider that maximizes PFD frequency self.regs[4] = ADF5356_REG4_R_COUNTER_UPDATE( @@ -193,7 +217,7 @@ class ADF5356: n_min, n_max = 75, 65535 # adjust reference divider to be able to match n_min constraint - while n_min * f_pfd > freq: + while int64(n_min) * f_pfd > freq: r = ADF5356_REG4_R_COUNTER_GET(self.regs[4]) self.regs[4] = ADF5356_REG4_R_COUNTER_UPDATE(self.regs[4], r + 1) f_pfd = self.f_pfd() @@ -207,7 +231,8 @@ class ADF5356: ) if not (n_min <= n <= n_max): - raise ValueError("Invalid INT value") + # NAC3TODO raise ValueError("Invalid INT value") + pass # configure PLL self.regs[0] = ADF5356_REG0_INT_VALUE_UPDATE(self.regs[0], n) @@ -221,10 +246,10 @@ class ADF5356: self.regs[6] = ADF5356_REG6_RF_DIVIDER_SELECT_UPDATE(self.regs[6], rf_div_sel) self.regs[6] = ADF5356_REG6_CP_BLEED_CURRENT_UPDATE( - self.regs[6], int32(floor(24 * f_pfd / (61.44 * MHz))) + self.regs[6], floor(24. * float(f_pfd) / (61.44 * MHz)) ) self.regs[9] = ADF5356_REG9_VCO_BAND_DIVISION_UPDATE( - self.regs[9], int32(ceil(f_pfd / 160e3)) + self.regs[9], ceil(float(f_pfd) / 160e3) ) # commit @@ -236,21 +261,21 @@ class ADF5356: Write all registers to the device. Attempts to lock the PLL. """ f_pfd = self.f_pfd() - delay(200 * us) # Slack + self.core.delay(200. * us) # Slack - if f_pfd <= 75.0 * MHz: + if f_pfd <= round64(75.0 * MHz): for i in range(13, 0, -1): self.write(self.regs[i]) - delay(200 * us) + self.core.delay(200. * us) self.write(self.regs[0] | ADF5356_REG0_AUTOCAL(1)) else: # AUTOCAL AT HALF PFD FREQUENCY # calculate PLL at f_pfd/2 n, frac1, (frac2_msb, frac2_lsb), (mod2_msb, mod2_lsb) = calculate_pll( - self.f_vco(), f_pfd >> 1 + self.f_vco(), f_pfd >> int64(1) ) - delay(200 * us) # Slack + self.core.delay(200. * us) # Slack self.write( 13 @@ -273,7 +298,7 @@ class ADF5356: ) self.write(1 | ADF5356_REG1_MAIN_FRAC_VALUE(frac1)) - delay(200 * us) + self.core.delay(200. * us) self.write(ADF5356_REG0_INT_VALUE(n) | ADF5356_REG0_AUTOCAL(1)) # RELOCK AT WANTED PFD FREQUENCY @@ -285,7 +310,7 @@ class ADF5356: self.write(self.regs[0] & ~ADF5356_REG0_AUTOCAL(1)) @portable - def f_pfd(self) -> TInt64: + def f_pfd(self) -> int64: """ Return the PFD frequency for the cached set of registers. """ @@ -295,35 +320,35 @@ class ADF5356: return self._compute_pfd_frequency(r, d, t) @portable - def f_vco(self) -> TInt64: + def f_vco(self) -> int64: """ Return the VCO frequency for the cached set of registers. """ - return int64( - self.f_pfd() + return round64( + float(self.f_pfd()) * ( - self.pll_n() - + (self.pll_frac1() + self.pll_frac2() / self.pll_mod2()) - / ADF5356_MODULUS1 - ) + float(self.pll_n()) + + (float(self.pll_frac1() + self.pll_frac2()) / float(self.pll_mod2())) + / float(ADF5356_MODULUS1) + ) ) @portable - def pll_n(self) -> TInt32: + def pll_n(self) -> int32: """ Return the PLL integer value (INT) for the cached set of registers. """ return ADF5356_REG0_INT_VALUE_GET(self.regs[0]) @portable - def pll_frac1(self) -> TInt32: + def pll_frac1(self) -> int32: """ Return the main fractional value (FRAC1) for the cached set of registers. """ return ADF5356_REG1_MAIN_FRAC_VALUE_GET(self.regs[1]) @portable - def pll_frac2(self) -> TInt32: + def pll_frac2(self) -> int32: """ Return the auxiliary fractional value (FRAC2) for the cached set of registers. """ @@ -332,7 +357,7 @@ class ADF5356: ) | ADF5356_REG2_AUX_FRAC_LSB_VALUE_GET(self.regs[2]) @portable - def pll_mod2(self) -> TInt32: + def pll_mod2(self) -> int32: """ Return the auxiliary modulus value (MOD2) for the cached set of registers. """ @@ -341,14 +366,14 @@ class ADF5356: ) | ADF5356_REG2_AUX_MOD_LSB_VALUE_GET(self.regs[2]) @portable - def ref_counter(self) -> TInt32: + def ref_counter(self) -> int32: """ Return the reference counter value (R) for the cached set of registers. """ return ADF5356_REG4_R_COUNTER_GET(self.regs[4]) @portable - def output_divider(self) -> TInt32: + def output_divider(self) -> int32: """ Return the value of the output A divider. """ @@ -398,7 +423,7 @@ class ADF5356: # single-ended reference mode is recommended # for references up to 250 MHz, even if the signal is differential - if self.sysclk <= 250 * MHz: + if self.sysclk <= 250.*MHz: self.regs[4] |= ADF5356_REG4_REF_MODE(0) else: self.regs[4] |= ADF5356_REG4_REF_MODE(1) @@ -440,7 +465,7 @@ class ADF5356: # charge pump bleed current self.regs[6] |= ADF5356_REG6_CP_BLEED_CURRENT( - int32(floor(24 * self.f_pfd() / (61.44 * MHz))) + floor(24. * float(self.f_pfd()) / (61.44 * MHz)) ) # direct feedback from VCO to N counter @@ -484,7 +509,7 @@ class ADF5356: ) self.regs[9] |= ADF5356_REG9_VCO_BAND_DIVISION( - int32(ceil(self.f_pfd() / 160e3)) + ceil(float(self.f_pfd()) / 160e3) ) # REG10 @@ -513,39 +538,39 @@ class ADF5356: self.regs[12] = int32(0x15FC) @portable - def _compute_pfd_frequency(self, r, d, t) -> TInt64: + def _compute_pfd_frequency(self, r: int32, d: int32, t: int32) -> int64: """ Calculate the PFD frequency from the given reference path parameters """ - return int64(self.sysclk * ((1 + d) / (r * (1 + t)))) + return round64(self.sysclk * (float(1 + d) / float(r * (1 + t)))) @portable - def _compute_reference_counter(self) -> TInt32: + def _compute_reference_counter(self) -> int32: """ Determine the reference counter R that maximizes the PFD frequency """ d = ADF5356_REG4_R_DOUBLER_GET(self.regs[4]) t = ADF5356_REG4_R_DIVIDER_GET(self.regs[4]) r = 1 - while self._compute_pfd_frequency(r, d, t) > ADF5356_MAX_FREQ_PFD: + while self._compute_pfd_frequency(r, d, t) > int64(ADF5356_MAX_FREQ_PFD): r += 1 - return int32(r) + return r @portable -def gcd(a, b): - while b: +def gcd(a: int64, b: int64) -> int64: + while b != int64(0): a, b = b, a % b return a @portable -def split_msb_lsb_28b(v): - return int32((v >> 14) & 0x3FFF), int32(v & 0x3FFF) +def split_msb_lsb_28b(v: int32) -> tuple[int32, int32]: + return (v >> 14) & 0x3FFF, v & 0x3FFF @portable -def calculate_pll(f_vco: TInt64, f_pfd: TInt64): +def calculate_pll(f_vco: int64, f_pfd: int64) -> tuple[int32, int32, tuple[int32, int32], tuple[int32, int32]]: """ Calculate fractional-N PLL parameters such that @@ -558,25 +583,23 @@ def calculate_pll(f_vco: TInt64, f_pfd: TInt64): :param f_pfd: PFD frequency :return: ``(n, frac1, (frac2_msb, frac2_lsb), (mod2_msb, mod2_lsb))`` """ - f_pfd = int64(f_pfd) - f_vco = int64(f_vco) # integral part n, r = int32(f_vco // f_pfd), f_vco % f_pfd # main fractional part - r *= ADF5356_MODULUS1 + r *= int64(ADF5356_MODULUS1) frac1, frac2 = int32(r // f_pfd), r % f_pfd # auxiliary fractional part mod2 = f_pfd - while mod2 > ADF5356_MAX_MODULUS2: - mod2 >>= 1 - frac2 >>= 1 + while mod2 > int64(ADF5356_MAX_MODULUS2): + mod2 >>= int64(1) + frac2 >>= int64(1) gcd_div = gcd(frac2, mod2) mod2 //= gcd_div frac2 //= gcd_div - return n, frac1, split_msb_lsb_28b(frac2), split_msb_lsb_28b(mod2) + return n, frac1, split_msb_lsb_28b(int32(frac2)), split_msb_lsb_28b(int32(mod2)) From b2f7022e0a22b6c902b086b10595f89e2cb28c86 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 28 Nov 2021 12:48:18 +0800 Subject: [PATCH 043/352] examples/nac3devices: demonstrate new capabilities --- artiq/examples/nac3devices/nac3devices.json | 5 +++++ artiq/examples/nac3devices/nac3devices.py | 24 +++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json index bd8d9043a..d7285f690 100644 --- a/artiq/examples/nac3devices/nac3devices.json +++ b/artiq/examples/nac3devices/nac3devices.json @@ -10,6 +10,11 @@ "type": "zotino", "ports": [0] }, + { + "type": "mirny", + "ports": [1], + "clk_sel": "mmcx" + }, { "type": "urukul", "dds": "ad9912", diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index 70d8eec6a..d6d50fa81 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -1,19 +1,26 @@ from artiq.experiment import * from artiq.coredevice.core import Core from artiq.coredevice.zotino import Zotino -from artiq.coredevice.urukul import CPLD +from artiq.coredevice.mirny import Mirny as MirnyCPLD +from artiq.coredevice.adf5356 import ADF5356 +from artiq.coredevice.urukul import CPLD as UrukulCPLD from artiq.coredevice.ad9912 import AD9912 + @nac3 class NAC3Devices(EnvExperiment): core: KernelInvariant[Core] zotino0: KernelInvariant[Zotino] - urukul0_cpld: KernelInvariant[CPLD] + mirny0_cpld: KernelInvariant[MirnyCPLD] + mirny0_ch0: KernelInvariant[ADF5356] + urukul0_cpld: KernelInvariant[UrukulCPLD] urukul0_ch0: KernelInvariant[AD9912] def build(self): self.setattr_device("core") self.setattr_device("zotino0") + self.setattr_device("mirny0_cpld") + self.setattr_device("mirny0_ch0") self.setattr_device("urukul0_cpld") self.setattr_device("urukul0_ch0") @@ -21,14 +28,23 @@ class NAC3Devices(EnvExperiment): def run(self): self.core.reset() self.core.delay(1.*ms) - self.zotino0.init(False) + self.zotino0.init() self.zotino0.set_leds(0x15) self.core.delay(1.*ms) self.zotino0.set_dac([1.2, -5.3, 3.4, 4.5], [0, 1, 2, 3]) self.core.break_realtime() self.core.delay(1.*ms) - self.urukul0_cpld.init(False) + self.mirny0_cpld.init() + self.mirny0_ch0.init() + self.mirny0_ch0.set_att_mu(160) + self.mirny0_ch0.sw.on() + self.core.break_realtime() + self.mirny0_ch0.set_frequency(2500.*MHz) + + self.core.break_realtime() + self.core.delay(1.*ms) + self.urukul0_cpld.init() self.urukul0_ch0.init() self.urukul0_ch0.sw.on() for i in range(10): From 233c5f4bfb6214f95bf0af217ee9c0f6b0c5c59d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 29 Nov 2021 18:14:47 +0800 Subject: [PATCH 044/352] update NAC3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index c04f9caed..7948cd9a8 100644 --- a/flake.lock +++ b/flake.lock @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1638016066, - "narHash": "sha256-bqpcyTh/CnpBj3rrIJnFgaSjVrgWaPNse68BsJvCGUA=", + "lastModified": 1638075448, + "narHash": "sha256-8eTjXvQ285w4958KCMScrr53IlfI1dFFmUl0LEAHRWg=", "ref": "master", - "rev": "7ee82de3123864dd2429771ccea9d6a4127a0f4d", - "revCount": 445, + "rev": "681d85d3bed6b3bf788806dc4f1c1682f8aa5fd9", + "revCount": 451, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 6a09b92fb33e6627911d775415e6e253c96775ba Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 29 Nov 2021 18:15:06 +0800 Subject: [PATCH 045/352] examples/nac3devices: fix mirny clocking --- artiq/examples/nac3devices/nac3devices.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json index d7285f690..99971df10 100644 --- a/artiq/examples/nac3devices/nac3devices.json +++ b/artiq/examples/nac3devices/nac3devices.json @@ -13,7 +13,8 @@ { "type": "mirny", "ports": [1], - "clk_sel": "mmcx" + "clk_sel": "mmcx", + "refclk": 125e6 }, { "type": "urukul", From 1bdf301e2aa738cbdf7b09f6479d785bf65d0e36 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 4 Dec 2021 19:03:15 +0800 Subject: [PATCH 046/352] flake: update NAC3 --- flake.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/flake.lock b/flake.lock index 7948cd9a8..f9d9428c3 100644 --- a/flake.lock +++ b/flake.lock @@ -18,17 +18,17 @@ }, "nixpkgs": { "locked": { - "lastModified": 1637636156, - "narHash": "sha256-E2ym4Vcpqu9JYoQDXJZR48gVD+LPPbaCoYveIk7Xu3Y=", + "lastModified": 1637328665, + "narHash": "sha256-z6ufVwquLM0IiNZxd5oT1M33Lv0aB3WICpk8ZKwpxjw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b026e1cf87a108dd06fe521f224fdc72fd0b013d", + "rev": "0f4b4b85d959200f52c16bbb74036994e7db5f74", "type": "github" }, "original": { "owner": "NixOS", - "ref": "release-21.11", "repo": "nixpkgs", + "rev": "0f4b4b85d959200f52c16bbb74036994e7db5f74", "type": "github" } }, @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1638075448, - "narHash": "sha256-8eTjXvQ285w4958KCMScrr53IlfI1dFFmUl0LEAHRWg=", + "lastModified": 1638611523, + "narHash": "sha256-/FZ72XsaFI9zL50omHznJCAykf8BOw7Tgtf8sThyurk=", "ref": "master", - "rev": "681d85d3bed6b3bf788806dc4f1c1682f8aa5fd9", - "revCount": 451, + "rev": "c98f367f90b7b658b3b6476aa111f68676f68f31", + "revCount": 481, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 2059fd375e33917a7fd238cc663e9aaf4e4b005a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 4 Dec 2021 19:03:39 +0800 Subject: [PATCH 047/352] language: add virtual --- artiq/language/core.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/artiq/language/core.py b/artiq/language/core.py index b4934dc3e..0cd28a8ff 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -11,7 +11,7 @@ from artiq.language import import_cache __all__ = [ - "KernelInvariant", "round64", + "KernelInvariant", "virtual", "round64", "extern", "kernel", "portable", "nac3", "rpc", "parallel", "sequential", "set_watchdog_factory", "watchdog", "TerminationRequested" @@ -19,9 +19,13 @@ __all__ = [ T = TypeVar('T') + class KernelInvariant(Generic[T]): pass +class virtual(Generic[T]): + pass + def round64(x): return round(x) From 12c39aaaae67da9fd574fad0306105d36b143975 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 4 Dec 2021 19:04:48 +0800 Subject: [PATCH 048/352] coredevice/adf5356: use nac3 floor/ceil --- artiq/coredevice/adf5356.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/artiq/coredevice/adf5356.py b/artiq/coredevice/adf5356.py index e357fefab..1c6812219 100644 --- a/artiq/coredevice/adf5356.py +++ b/artiq/coredevice/adf5356.py @@ -9,7 +9,7 @@ on Mirny-style prefixed SPI buses. # https://www.analog.com/media/en/technical-documentation/user-guides/EV-ADF5355SD1Z-UG-1087.pdf from numpy import int32, int64 -# NAC3TODO from math import floor, ceil +from math import floor, ceil from artiq.language.core import nac3, KernelInvariant, kernel, portable, round64 from artiq.language.units import us, GHz, MHz @@ -20,14 +20,6 @@ from artiq.coredevice.spi2 import * from artiq.coredevice.adf5356_reg import * -# NAC3TODO -@portable -def floor(x: float) -> int32: - return 0 -@portable -def ceil(x: float) -> int32: - return 0 -# SPI_CONFIG = ( 0 * SPI_OFFLINE From e34f4cc99bf7f04d49db015e0c7d6b40811de4eb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 4 Dec 2021 20:13:00 +0800 Subject: [PATCH 049/352] language: add floor64 and ceil64 --- artiq/language/core.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/artiq/language/core.py b/artiq/language/core.py index 0cd28a8ff..f2e9bc988 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -6,12 +6,14 @@ from typing import Generic, TypeVar from functools import wraps from inspect import getfullargspec, getmodule from types import SimpleNamespace +from math import floor, ceil from artiq.language import import_cache __all__ = [ - "KernelInvariant", "virtual", "round64", + "KernelInvariant", "virtual", + "round64", "floor64", "ceil64", "extern", "kernel", "portable", "nac3", "rpc", "parallel", "sequential", "set_watchdog_factory", "watchdog", "TerminationRequested" @@ -30,6 +32,12 @@ class virtual(Generic[T]): def round64(x): return round(x) +def floor64(x): + return floor(x) + +def ceil64(x): + return ceil(x) + _allow_registration = True # Delay NAC3 analysis until all referenced variables are supposed to exist on the CPython side. From 3f3186005ec5ec45961fccb4ff7068c525d442ff Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 5 Dec 2021 14:31:49 +0800 Subject: [PATCH 050/352] flake: get rid of TARGET_AR --- flake.lock | 8 ++++---- flake.nix | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index f9d9428c3..573a7d19c 100644 --- a/flake.lock +++ b/flake.lock @@ -60,11 +60,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1636527305, - "narHash": "sha256-/2XTejqj0Bo81HaTrlTSWwInnWwsuqnq+CURXbpIrkA=", + "lastModified": 1638683371, + "narHash": "sha256-sm2SxHmEGfE56+V+joDHMjpOaxg8+t3EJEk1d11C1E0=", "ref": "master", - "rev": "f5203e406520874e15ab5d070058ef642fc57fd9", - "revCount": 2417, + "rev": "71b74f87b41c56a6c6d767cdfde0356c15a379a7", + "revCount": 2418, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" diff --git a/flake.nix b/flake.nix index c68745836..ba72ae779 100644 --- a/flake.nix +++ b/flake.nix @@ -202,7 +202,6 @@ ln -s $ARTIQ_PATH/firmware/Cargo.lock . cargoSetupPostUnpackHook cargoSetupPostPatchHook - export TARGET_AR=llvm-ar ${buildCommand} ''; doCheck = true; @@ -316,7 +315,6 @@ packages.x86_64-linux.vivado packages.x86_64-linux.openocd-bscanspi ]; - TARGET_AR="llvm-ar"; }; hydraJobs = { From 61d3e22ea88000065c18921e714554d4221795b7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 5 Dec 2021 14:37:33 +0800 Subject: [PATCH 051/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 573a7d19c..072ef9421 100644 --- a/flake.lock +++ b/flake.lock @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1638611523, - "narHash": "sha256-/FZ72XsaFI9zL50omHznJCAykf8BOw7Tgtf8sThyurk=", + "lastModified": 1638686158, + "narHash": "sha256-x3DSzTZEhpTt2PKIx/HZ+5PuD56ytc6HOZtra/yyInI=", "ref": "master", - "rev": "c98f367f90b7b658b3b6476aa111f68676f68f31", - "revCount": 481, + "rev": "d2919b9620c88756b73aa0cb13f9f014703b67c4", + "revCount": 488, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 31ac6881df56757ca2efd7be4f24c904b264f1d2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Dec 2021 12:21:52 +0800 Subject: [PATCH 052/352] update NAC3, restore original delays --- artiq/coredevice/ad53xx.py | 4 ++-- artiq/coredevice/ad9912.py | 2 +- artiq/examples/nac3devices/nac3devices.py | 5 ----- flake.lock | 8 ++++---- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 0266ab836..697951343 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -196,7 +196,7 @@ class AD53xx: if (ctrl & 0b10000) != 0: # NAC3TODO raise ValueError("DAC over temperature") pass - self.core.delay(125.*us) # NAC3TODO try to restore original 25us after kernel invariants + self.core.delay(25.*us) self.bus.write( # enable power and overtemperature shutdown (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_CONTROL | 0b0010) << 8) if not blind: @@ -204,7 +204,7 @@ class AD53xx: if (ctrl & 0b10111) != 0b00010: # NAC3TODO raise ValueError("DAC CONTROL readback mismatch") pass - self.core.delay(115.*us) # NAC3TODO try to restore original 15us after kernel invariants + self.core.delay(15.*us) @kernel def read_reg(self, channel: int32 = 0, op: int32 = AD53XX_READ_X1A) -> int32: diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 2be434d45..5c294d1de 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -108,7 +108,7 @@ class AD9912: if (prodid != 0x1982) and (prodid != 0x1902): # NAC3TODO raise ValueError("Urukul AD9912 product id mismatch") pass - self.core.delay(300. * us) # NAC3TODO try to restore 50us after kernel invariants are implemented + self.core.delay(50. * us) # HSTL power down, CMOS power down self.write(AD9912_PWRCNTRL1, 0x80, 1) self.cpld.io_update.pulse(2. * us) diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index d6d50fa81..e01313428 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -27,23 +27,18 @@ class NAC3Devices(EnvExperiment): @kernel def run(self): self.core.reset() - self.core.delay(1.*ms) self.zotino0.init() self.zotino0.set_leds(0x15) - self.core.delay(1.*ms) self.zotino0.set_dac([1.2, -5.3, 3.4, 4.5], [0, 1, 2, 3]) self.core.break_realtime() - self.core.delay(1.*ms) self.mirny0_cpld.init() self.mirny0_ch0.init() self.mirny0_ch0.set_att_mu(160) self.mirny0_ch0.sw.on() - self.core.break_realtime() self.mirny0_ch0.set_frequency(2500.*MHz) self.core.break_realtime() - self.core.delay(1.*ms) self.urukul0_cpld.init() self.urukul0_ch0.init() self.urukul0_ch0.sw.on() diff --git a/flake.lock b/flake.lock index 072ef9421..eeb37f257 100644 --- a/flake.lock +++ b/flake.lock @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1638686158, - "narHash": "sha256-x3DSzTZEhpTt2PKIx/HZ+5PuD56ytc6HOZtra/yyInI=", + "lastModified": 1638707403, + "narHash": "sha256-NcGX9uS5/Gb1geUo4NEZsX5b+Eq9uWkT04iwUVQnHBg=", "ref": "master", - "rev": "d2919b9620c88756b73aa0cb13f9f014703b67c4", - "revCount": 488, + "rev": "6d00d4dabb54f6944a9c97981a1d3416093a3df9", + "revCount": 490, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 60cbde08200135d225d9d1de324d64219ee19547 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 9 Dec 2021 12:35:33 +0800 Subject: [PATCH 053/352] flake: update dependencies --- flake.lock | 22 +++++++++++----------- flake.nix | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index eeb37f257..077b38dc2 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1637337116, - "narHash": "sha256-LKqAcdL+woWeYajs02bDQ7q8rsqgXuzhC354NoRaV80=", + "lastModified": 1638887313, + "narHash": "sha256-FMYV6rVtvSIfthgC1sK1xugh3y7muoQcvduMdriz4ag=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "cbc7435f5b0b3d17b16fb1d20cf7b616eec5e093", + "rev": "7c1e8b1dd6ed0043fb4ee0b12b815256b0b9de6f", "type": "github" }, "original": { @@ -18,17 +18,17 @@ }, "nixpkgs": { "locked": { - "lastModified": 1637328665, - "narHash": "sha256-z6ufVwquLM0IiNZxd5oT1M33Lv0aB3WICpk8ZKwpxjw=", + "lastModified": 1638887115, + "narHash": "sha256-emjtIeqyJ84Eb3X7APJruTrwcfnHQKs55XGljj62prs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0f4b4b85d959200f52c16bbb74036994e7db5f74", + "rev": "1bd4bbd49bef217a3d1adea43498270d6e779d65", "type": "github" }, "original": { "owner": "NixOS", + "ref": "nixos-21.11", "repo": "nixpkgs", - "rev": "0f4b4b85d959200f52c16bbb74036994e7db5f74", "type": "github" } }, @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1638707403, - "narHash": "sha256-NcGX9uS5/Gb1geUo4NEZsX5b+Eq9uWkT04iwUVQnHBg=", + "lastModified": 1638985025, + "narHash": "sha256-0Cw40IFu+DbCjrfYYlN4eleOiKkTaxO9Y90tdxfXjXQ=", "ref": "master", - "rev": "6d00d4dabb54f6944a9c97981a1d3416093a3df9", - "revCount": 490, + "rev": "4d2fd9582a61c0d12ebb83373736f2b41b0b4535", + "revCount": 497, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, diff --git a/flake.nix b/flake.nix index ba72ae779..b18762545 100644 --- a/flake.nix +++ b/flake.nix @@ -10,7 +10,7 @@ outputs = { self, mozilla-overlay, src-sipyco, src-nac3, src-migen, src-misoc }: let - pkgs = import src-nac3.nixpkgs-patched { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; }; + pkgs = import src-nac3.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; }; rustManifest = pkgs.fetchurl { url = "https://static.rust-lang.org/dist/2021-01-29/channel-rust-nightly.toml"; sha256 = "sha256-EZKgw89AH4vxaJpUHmIMzMW/80wAFQlfcxRoBD9nz0c="; From dad23b6981e8cf3eab366f39cfcc0f4fefb48e00 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 9 Dec 2021 12:40:01 +0800 Subject: [PATCH 054/352] coredevice/ad53xx: use len(list) --- artiq/coredevice/ad53xx.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 697951343..f8bbc76bb 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -337,11 +337,9 @@ class AD53xx: # t10: max busy period after writing to DAC registers t_10 = self.core.seconds_to_mu(1500.*ns) - # NAC3TODO len(values) https://git.m-labs.hk/M-Labs/nac3/issues/103 - len_values = 4 # compensate all delays that will be applied - delay_mu(-t_10-int64(len_values)*self.bus.xfer_duration_mu) - for i in range(len_values): + delay_mu(-t_10-int64(len(values))*self.bus.xfer_duration_mu) + for i in range(len(values)): self.write_dac_mu(channels[i], values[i]) delay_mu(t_10) self.load() From d853604380af39b5b5f3c1eb57655796d87acac6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Dec 2021 17:27:00 +0800 Subject: [PATCH 055/352] flake: update dependencies --- flake.lock | 22 +++++++++++----------- flake.nix | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index 077b38dc2..db33b95d6 100644 --- a/flake.lock +++ b/flake.lock @@ -44,11 +44,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1636715924, - "narHash": "sha256-V3ThFSo2d7OC4SHE0lCkKGQKeFXmvxtwZRWe5NMU3nM=", + "lastModified": 1639659493, + "narHash": "sha256-qpVj/yJf4hDDc99XXpVPH4EbLC8aCmEtACn5qNc3DGI=", "owner": "m-labs", "repo": "migen", - "rev": "9a0be7a4210ff96043412539eb5388659b81831d", + "rev": "ac703010eaa06ac9b6e32f97c6fa98b15de22b31", "type": "github" }, "original": { @@ -80,15 +80,15 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1638985025, - "narHash": "sha256-0Cw40IFu+DbCjrfYYlN4eleOiKkTaxO9Y90tdxfXjXQ=", - "ref": "master", - "rev": "4d2fd9582a61c0d12ebb83373736f2b41b0b4535", - "revCount": 497, + "lastModified": 1639363473, + "narHash": "sha256-PAEDC15ToLc3PW9fXi+qoR7VfPsZnmRWc6BssGGOWgg=", + "rev": "2c6601d97c111f07278b51272ffd1539847cad9f", + "revCount": 499, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, "original": { + "rev": "2c6601d97c111f07278b51272ffd1539847cad9f", "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" } @@ -96,11 +96,11 @@ "src-sipyco": { "flake": false, "locked": { - "lastModified": 1632832039, - "narHash": "sha256-GYXXCCOxNZyy6j7qScB3/QWUUCEVX+4tM4bXXVGXty0=", + "lastModified": 1639887898, + "narHash": "sha256-slXtLgkTK9HLifwkSWRgQlxSzSXr2kRDPAZpp6CaqKc=", "owner": "m-labs", "repo": "sipyco", - "rev": "b83d8e5d82b25dba9393f0c12bdc5253f8138545", + "rev": "854bba70ee06407cede7048d739152690d753d55", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index b18762545..ebe815413 100644 --- a/flake.nix +++ b/flake.nix @@ -3,7 +3,7 @@ inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; }; inputs.src-sipyco = { url = github:m-labs/sipyco; flake = false; }; - inputs.src-nac3 = { type = "git"; url = "https://git.m-labs.hk/M-Labs/nac3.git"; }; + inputs.src-nac3 = { type = "git"; url = "https://git.m-labs.hk/M-Labs/nac3.git"; rev = "2c6601d97c111f07278b51272ffd1539847cad9f"; }; inputs.src-migen = { url = github:m-labs/migen; flake = false; }; inputs.src-misoc = { type = "git"; url = "https://github.com/m-labs/misoc.git"; submodules = true; flake = false; }; From 088c3b470ebcd6aeed5c95bcb5931739e1a410f6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Dec 2021 17:56:40 +0800 Subject: [PATCH 056/352] update NAC3, use new Kernel type annotation --- artiq/coredevice/ad53xx.py | 4 ++-- artiq/coredevice/adf5356.py | 8 ++++---- artiq/coredevice/mirny.py | 8 ++++---- artiq/coredevice/spi2.py | 4 ++-- artiq/coredevice/urukul.py | 8 ++++---- artiq/language/core.py | 5 ++++- 6 files changed, 20 insertions(+), 17 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index f8bbc76bb..0abfd76d9 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -10,7 +10,7 @@ time is an error. from numpy import int32, int64 -from artiq.language.core import nac3, kernel, portable, KernelInvariant +from artiq.language.core import nac3, kernel, portable, Kernel, KernelInvariant from artiq.language.units import ns, us from artiq.coredevice.core import Core from artiq.coredevice.ttl import TTLOut @@ -150,7 +150,7 @@ class AD53xx: div_write: KernelInvariant[int32] div_read: KernelInvariant[int32] vref: KernelInvariant[float] - offset_dacs: int32 + offset_dacs: Kernel[int32] def __init__(self, dmgr, spi_device, ldac_device=None, clr_device=None, chip_select=1, div_write=4, div_read=16, vref=5., diff --git a/artiq/coredevice/adf5356.py b/artiq/coredevice/adf5356.py index 1c6812219..e783c8088 100644 --- a/artiq/coredevice/adf5356.py +++ b/artiq/coredevice/adf5356.py @@ -11,7 +11,7 @@ on Mirny-style prefixed SPI buses. from numpy import int32, int64 from math import floor, ceil -from artiq.language.core import nac3, KernelInvariant, kernel, portable, round64 +from artiq.language.core import nac3, Kernel, KernelInvariant, kernel, portable, round64 from artiq.language.units import us, GHz, MHz from artiq.coredevice.core import Core from artiq.coredevice.mirny import Mirny @@ -58,9 +58,9 @@ class ADF5356: channel: KernelInvariant[int32] sw: KernelInvariant[TTLOut] sysclk: KernelInvariant[float] - regs: list[int32] - ref_doubler: bool - ref_divider: bool + regs: Kernel[list[int32]] + ref_doubler: Kernel[bool] + ref_divider: Kernel[bool] def __init__( self, diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py index 364b71298..83e00eb2d 100644 --- a/artiq/coredevice/mirny.py +++ b/artiq/coredevice/mirny.py @@ -1,7 +1,7 @@ """RTIO driver for Mirny (4 channel GHz PLLs) """ -from artiq.language.core import nac3, KernelInvariant, kernel +from artiq.language.core import nac3, Kernel, KernelInvariant, kernel from artiq.language.units import us from numpy import int32 @@ -51,9 +51,9 @@ class Mirny: core: KernelInvariant[Core] bus: KernelInvariant[SPIMaster] refclk: KernelInvariant[float] - clk_sel_hw_rev: list[int32] - hw_rev: int32 - clk_sel: int32 + clk_sel_hw_rev: Kernel[list[int32]] + hw_rev: Kernel[int32] + clk_sel: Kernel[int32] def __init__(self, dmgr, spi_device, refclk=100e6, clk_sel="XO", core_device="core"): self.core = dmgr.get(core_device) diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index ae1bd2ef4..3b0147a6a 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -9,7 +9,7 @@ time is an error. from numpy import int32, int64 -from artiq.language.core import nac3, KernelInvariant, kernel, portable, extern +from artiq.language.core import nac3, Kernel, KernelInvariant, kernel, portable, extern from artiq.coredevice.core import Core from artiq.coredevice.rtio import rtio_output, rtio_input_data @@ -68,7 +68,7 @@ class SPIMaster: core: KernelInvariant[Core] ref_period_mu: KernelInvariant[int64] channel: KernelInvariant[int32] - xfer_duration_mu: int64 + xfer_duration_mu: Kernel[int64] def __init__(self, dmgr, channel, div=0, length=0, core_device="core"): self.core = dmgr.get(core_device) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 21c3bbf34..9ca7751b1 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -1,6 +1,6 @@ from numpy import int32, int64 -from artiq.language.core import nac3, KernelInvariant, kernel, portable +from artiq.language.core import nac3, Kernel, KernelInvariant, kernel, portable from artiq.language.units import us, ms from artiq.coredevice.core import Core @@ -157,9 +157,9 @@ class CPLD: io_update: KernelInvariant[TTLOut] clk_div: KernelInvariant[int32] sync: KernelInvariant[_DummySync] - cfg_reg: int32 - att_reg: int32 - sync_div: int32 + cfg_reg: Kernel[int32] + att_reg: Kernel[int32] + sync_div: Kernel[int32] def __init__(self, dmgr, spi_device, io_update_device=None, dds_reset_device=None, sync_device=None, diff --git a/artiq/language/core.py b/artiq/language/core.py index f2e9bc988..b9f5fe8a9 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -12,7 +12,7 @@ from artiq.language import import_cache __all__ = [ - "KernelInvariant", "virtual", + "Kernel", "KernelInvariant", "virtual", "round64", "floor64", "ceil64", "extern", "kernel", "portable", "nac3", "rpc", "parallel", "sequential", @@ -22,6 +22,9 @@ __all__ = [ T = TypeVar('T') +class Kernel(Generic[T]): + pass + class KernelInvariant(Generic[T]): pass From 243fe5ea881bd7481a29e622912b1e5d3c3554ef Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Dec 2021 18:02:15 +0800 Subject: [PATCH 057/352] flake: update nac3 --- flake.lock | 10 +++++----- flake.nix | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index db33b95d6..e79908d7a 100644 --- a/flake.lock +++ b/flake.lock @@ -80,15 +80,15 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1639363473, - "narHash": "sha256-PAEDC15ToLc3PW9fXi+qoR7VfPsZnmRWc6BssGGOWgg=", - "rev": "2c6601d97c111f07278b51272ffd1539847cad9f", - "revCount": 499, + "lastModified": 1639993482, + "narHash": "sha256-0mukHrr9o9EkQasf5MI7doLbYNS0o+2uo4V9wuSx5wc=", + "ref": "master", + "rev": "e2b44a066be5244ca044f643b57697aa962710dd", + "revCount": 508, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, "original": { - "rev": "2c6601d97c111f07278b51272ffd1539847cad9f", "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" } diff --git a/flake.nix b/flake.nix index ebe815413..b18762545 100644 --- a/flake.nix +++ b/flake.nix @@ -3,7 +3,7 @@ inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; }; inputs.src-sipyco = { url = github:m-labs/sipyco; flake = false; }; - inputs.src-nac3 = { type = "git"; url = "https://git.m-labs.hk/M-Labs/nac3.git"; rev = "2c6601d97c111f07278b51272ffd1539847cad9f"; }; + inputs.src-nac3 = { type = "git"; url = "https://git.m-labs.hk/M-Labs/nac3.git"; }; inputs.src-migen = { url = github:m-labs/migen; flake = false; }; inputs.src-misoc = { type = "git"; url = "https://github.com/m-labs/misoc.git"; submodules = true; flake = false; }; From 97365de104d29cd2a9d50b2b486c2eef27cf3f9e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Dec 2021 18:18:43 +0800 Subject: [PATCH 058/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index e79908d7a..e630fd814 100644 --- a/flake.lock +++ b/flake.lock @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1639993482, - "narHash": "sha256-0mukHrr9o9EkQasf5MI7doLbYNS0o+2uo4V9wuSx5wc=", + "lastModified": 1639995225, + "narHash": "sha256-DEd0ztj47BLG7CyJiEsCcJx3ZBWVjns/HtwXk1fe5TM=", "ref": "master", - "rev": "e2b44a066be5244ca044f643b57697aa962710dd", - "revCount": 508, + "rev": "0ff995722c99c9b4260eff9d94c581be0088f7f6", + "revCount": 509, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 51cb8adba092850a826af0817f6db590b7f08151 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 26 Dec 2021 08:50:02 +0800 Subject: [PATCH 059/352] update NAC3 --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index e630fd814..f280baebd 100644 --- a/flake.lock +++ b/flake.lock @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1638887115, - "narHash": "sha256-emjtIeqyJ84Eb3X7APJruTrwcfnHQKs55XGljj62prs=", + "lastModified": 1640264129, + "narHash": "sha256-gfTFmZhnHE9G+Tr0fdMmo6p/FHi5QpkO9oPPYSu6JO0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1bd4bbd49bef217a3d1adea43498270d6e779d65", + "rev": "1158f3463912d54cc981d61213839ec6c02570d3", "type": "github" }, "original": { @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1639995225, - "narHash": "sha256-DEd0ztj47BLG7CyJiEsCcJx3ZBWVjns/HtwXk1fe5TM=", + "lastModified": 1640478927, + "narHash": "sha256-IwIoCSGm1sdStSFHDUB8xp4Yr9sMV7o4XLyWFGMdEgA=", "ref": "master", - "rev": "0ff995722c99c9b4260eff9d94c581be0088f7f6", - "revCount": 509, + "rev": "86005da8e1e2b447cba39a6a4482da929e1915be", + "revCount": 521, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From c795cb40ea0a46a05f452781d57526ed46cc0895 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Dec 2021 11:49:01 +0800 Subject: [PATCH 060/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index f280baebd..43f78521a 100644 --- a/flake.lock +++ b/flake.lock @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1640478927, - "narHash": "sha256-IwIoCSGm1sdStSFHDUB8xp4Yr9sMV7o4XLyWFGMdEgA=", + "lastModified": 1640660357, + "narHash": "sha256-X0X00CCMZTl+5g6hREghnXOwzqbfijUtGoWm4gHQ0nI=", "ref": "master", - "rev": "86005da8e1e2b447cba39a6a4482da929e1915be", - "revCount": 521, + "rev": "9cc9a0284a15293421d2733b3fe4191ac72b680c", + "revCount": 531, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 17d217d47d2e6cc6a142d739fc6622ed515ee1eb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 4 Jan 2022 22:09:52 +0800 Subject: [PATCH 061/352] flake: update nac3 --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 43f78521a..4dff9bbdd 100644 --- a/flake.lock +++ b/flake.lock @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1640264129, - "narHash": "sha256-gfTFmZhnHE9G+Tr0fdMmo6p/FHi5QpkO9oPPYSu6JO0=", + "lastModified": 1641244400, + "narHash": "sha256-8i4oasWEz/2y9U+F1XU15jfwSbd5YOEBh2tyBBm/W8E=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1158f3463912d54cc981d61213839ec6c02570d3", + "rev": "c6019d8efb5530dcf7ce98086b8e091be5ff900a", "type": "github" }, "original": { @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1640660357, - "narHash": "sha256-X0X00CCMZTl+5g6hREghnXOwzqbfijUtGoWm4gHQ0nI=", + "lastModified": 1641304829, + "narHash": "sha256-bXD7l+MMCgUzHPGybsF3poDLU5B8QLpbmuXecIOtMbk=", "ref": "master", - "rev": "9cc9a0284a15293421d2733b3fe4191ac72b680c", - "revCount": 531, + "rev": "52ccf31bb17f804f2700eb88de4ddc61e9a38476", + "revCount": 536, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 59af28d6f7af07f2184465e2e6c6f2ace99b4d1c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 4 Jan 2022 22:11:10 +0800 Subject: [PATCH 062/352] flake: use LLVM 13 for consistency with NAC3 --- flake.nix | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.nix b/flake.nix index b18762545..438eec67e 100644 --- a/flake.nix +++ b/flake.nix @@ -76,7 +76,7 @@ nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; # keep llvm_x and lld_x in sync with nac3 - propagatedBuildInputs = [ pkgs.llvm_12 pkgs.lld_12 src-nac3.packages.x86_64-linux.nac3artiq sipyco ] + propagatedBuildInputs = [ pkgs.llvm_13 pkgs.lld_13 src-nac3.packages.x86_64-linux.nac3artiq sipyco ] ++ (with pkgs.python3Packages; [ pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial h5py pyqt5 qasync ]); dontWrapQtApps = true; @@ -93,8 +93,8 @@ "--set FONTCONFIG_FILE ${pkgs.fontconfig.out}/etc/fonts/fonts.conf" ]; - # FIXME: automatically propagate lld_12 llvm_12 dependencies - checkInputs = [ pkgs.lld_12 pkgs.llvm_12 ]; + # FIXME: automatically propagate lld_13 llvm_13 dependencies + checkInputs = [ pkgs.lld_13 pkgs.llvm_13 ]; checkPhase = '' python -m unittest discover -v artiq.test ''; @@ -189,9 +189,9 @@ (pkgs.python3.withPackages(ps: [ migen misoc artiq ])) rustPlatform.rust.rustc rustPlatform.rust.cargo - pkgs.llvmPackages_12.clang-unwrapped - pkgs.llvm_12 - pkgs.lld_12 + pkgs.llvmPackages_13.clang-unwrapped + pkgs.llvm_13 + pkgs.lld_13 vivado rustPlatform.cargoSetupHook cargo-xbuild @@ -307,9 +307,9 @@ rustPlatform.rust.rustc rustPlatform.rust.cargo cargo-xbuild - pkgs.llvmPackages_12.clang-unwrapped - pkgs.llvm_12 - pkgs.lld_12 + pkgs.llvmPackages_13.clang-unwrapped + pkgs.llvm_13 + pkgs.lld_13 # use the vivado-env command to enter a FHS shell that lets you run the Vivado installer packages.x86_64-linux.vivadoEnv packages.x86_64-linux.vivado From 4ad8f5d6c73b4248f06264fddbb8fa5dd5382d4e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 4 Jan 2022 22:20:12 +0800 Subject: [PATCH 063/352] flake: reexport and use mimalloc-enabled Python --- flake.nix | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 438eec67e..fab2f40f2 100644 --- a/flake.nix +++ b/flake.nix @@ -272,6 +272,7 @@ in rec { packages.x86_64-linux = rec { inherit migen misoc vivadoEnv vivado openocd-bscanspi artiq; + inherit (src-nac3.packages.x86_64-linux) python3-mimalloc; artiq-board-kc705-nist_clock = makeArtiqBoardPackage { target = "kc705"; variant = "nist_clock"; @@ -298,12 +299,12 @@ }; }; - defaultPackage.x86_64-linux = pkgs.python3.withPackages(ps: [ packages.x86_64-linux.artiq ]); + defaultPackage.x86_64-linux = packages.x86_64-linux.python3-mimalloc.withPackages(ps: [ packages.x86_64-linux.artiq ]); devShell.x86_64-linux = pkgs.mkShell { name = "artiq-dev-shell"; buildInputs = [ - (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc jesd204b artiq ps.paramiko ps.jsonschema microscope ])) + (packages.x86_64-linux.python3-mimalloc.withPackages(ps: with packages.x86_64-linux; [ migen misoc jesd204b artiq ps.paramiko ps.jsonschema microscope ])) rustPlatform.rust.rustc rustPlatform.rust.cargo cargo-xbuild From 02555e48a0eff8800d6ec86954c0bd7ff1a028e1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Jan 2022 11:45:10 +0800 Subject: [PATCH 064/352] update NAC3, use power operator --- artiq/coredevice/ttl.py | 6 ++---- flake.lock | 8 ++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 45c3d6fe9..9143dc7c9 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -482,16 +482,14 @@ class TTLClockGen: """Returns the frequency tuning word corresponding to the given frequency. """ - # NAC3TODO return round64(2**self.acc_width*frequency*self.core.coarse_ref_period) - return 0 + return round(2.**float(self.acc_width)*frequency*self.core.coarse_ref_period) @portable def ftw_to_frequency(self, ftw: int32) -> float: """Returns the frequency corresponding to the given frequency tuning word. """ - # NAC3TODO return float(ftw)/self.core.coarse_ref_period/2**int64(self.acc_width) - return 0.0 + return float(ftw)/self.core.coarse_ref_period/2.**float(self.acc_width) @kernel def set_mu(self, frequency: int32): diff --git a/flake.lock b/flake.lock index 4dff9bbdd..4d6488c01 100644 --- a/flake.lock +++ b/flake.lock @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1641304829, - "narHash": "sha256-bXD7l+MMCgUzHPGybsF3poDLU5B8QLpbmuXecIOtMbk=", + "lastModified": 1641699066, + "narHash": "sha256-tjcdd8h9Jy1JzZKPjCVGYJtC4sXLmteMrpVeXs0Cff4=", "ref": "master", - "rev": "52ccf31bb17f804f2700eb88de4ddc61e9a38476", - "revCount": 536, + "rev": "8ef9e74aaf0e548d4b636a1d1c1cb208b26b04c1", + "revCount": 544, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 1c56b08a4b40e18641d33014e34d861a6fc469e3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Jan 2022 21:08:15 +0800 Subject: [PATCH 065/352] flake: update dependencies --- flake.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/flake.lock b/flake.lock index 4d6488c01..e52ccaf57 100644 --- a/flake.lock +++ b/flake.lock @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1641244400, - "narHash": "sha256-8i4oasWEz/2y9U+F1XU15jfwSbd5YOEBh2tyBBm/W8E=", + "lastModified": 1642522226, + "narHash": "sha256-m/j9U8KYuwwxjwgRCjmEj8ejftvdMLJ+NGXh/L2I4FU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c6019d8efb5530dcf7ce98086b8e091be5ff900a", + "rev": "610d4ea2750e064bf34b33fa38cb671edd893d3d", "type": "github" }, "original": { @@ -60,11 +60,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1638683371, - "narHash": "sha256-sm2SxHmEGfE56+V+joDHMjpOaxg8+t3EJEk1d11C1E0=", + "lastModified": 1641889368, + "narHash": "sha256-0Ai25lry9ju1HxFmfMRNKG8mamBqvw+kvDfpuK8Dtjo=", "ref": "master", - "rev": "71b74f87b41c56a6c6d767cdfde0356c15a379a7", - "revCount": 2418, + "rev": "7242dc5a41732135425acc4871487461dfae6c66", + "revCount": 2419, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1641699066, - "narHash": "sha256-tjcdd8h9Jy1JzZKPjCVGYJtC4sXLmteMrpVeXs0Cff4=", + "lastModified": 1642598227, + "narHash": "sha256-lx0pb3ZI4CJc0qzkV3ktQFoSw1edAwZpwNGpQlwyq/8=", "ref": "master", - "rev": "8ef9e74aaf0e548d4b636a1d1c1cb208b26b04c1", - "revCount": 544, + "rev": "f478c6afcc07e5c966c762c4378e8c5ddd6b1ead", + "revCount": 555, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, @@ -96,11 +96,11 @@ "src-sipyco": { "flake": false, "locked": { - "lastModified": 1639887898, - "narHash": "sha256-slXtLgkTK9HLifwkSWRgQlxSzSXr2kRDPAZpp6CaqKc=", + "lastModified": 1641866796, + "narHash": "sha256-TSH0IgNbi9IcMcBDb2nWRphKlxstbWeATjrGbi6K2m0=", "owner": "m-labs", "repo": "sipyco", - "rev": "854bba70ee06407cede7048d739152690d753d55", + "rev": "b04234c49379cd446d4cb3346d4741868d86841a", "type": "github" }, "original": { From c8ec2b0d7f1d5de98b2b146de189d9197ad3dd74 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 26 Jan 2022 07:23:57 +0800 Subject: [PATCH 066/352] flake: update dependencies --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index e52ccaf57..cf8c176d3 100644 --- a/flake.lock +++ b/flake.lock @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1642598227, - "narHash": "sha256-lx0pb3ZI4CJc0qzkV3ktQFoSw1edAwZpwNGpQlwyq/8=", + "lastModified": 1643140707, + "narHash": "sha256-sCfXT/4ozkYfR7HxvHrq65CKaSUpaJ3NGVoYMA8YyMc=", "ref": "master", - "rev": "f478c6afcc07e5c966c762c4378e8c5ddd6b1ead", - "revCount": 555, + "rev": "43048eb8d8273a7c17bb216623482b60649547b0", + "revCount": 567, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From f2f2e12b91ea5a7e2c25bce00c169a0e798427d7 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Sat, 12 Feb 2022 22:32:21 +0800 Subject: [PATCH 067/352] language: implemented embedding map and exception --- artiq/coredevice/comm_kernel.py | 12 ++-- artiq/coredevice/core.py | 110 ++++++++++++++++++++++++++++++-- artiq/frontend/artiq_compile.py | 5 +- artiq/language/__init__.py | 2 + artiq/language/core.py | 2 +- artiq/language/embedding_map.py | 62 ++++++++++++++++++ 6 files changed, 177 insertions(+), 16 deletions(-) create mode 100644 artiq/language/embedding_map.py diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index e6551cb0a..3f9c70cdc 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -553,7 +553,7 @@ class CommKernel: if service_id == 0: def service(obj, attr, value): return setattr(obj, attr, value) else: - service = embedding_map.retrieve_object(service_id) + service = embedding_map.retrieve_function(service_id) logger.debug("rpc service: [%d]%r%s %r %r -> %s", service_id, service, (" (async)" if is_async else ""), args, kwargs, return_tags) @@ -622,7 +622,7 @@ class CommKernel: result, result, service) self._flush() - def _serve_exception(self, embedding_map, symbolizer, demangler): + def _serve_exception(self, embedding_map, symbolizer): exception_count = self._read_int32() nested_exceptions = [] @@ -646,10 +646,6 @@ class CommKernel: nested_exceptions.append([name, message, params, filename, line, column, function]) - demangled_names = demangler([ex[6] for ex in nested_exceptions]) - for i in range(exception_count): - nested_exceptions[i][6] = demangled_names[i] - exception_info = [] for _ in range(exception_count): sp = self._read_int32() @@ -689,13 +685,13 @@ class CommKernel: logger.warning(f"{(', '.join(errors[:-1]) + ' and ') if len(errors) > 1 else ''}{errors[-1]} " f"reported during kernel execution") - def serve(self, embedding_map, symbolizer, demangler): + def serve(self, embedding_map, symbolizer): while True: self._read_header() if self._read_type == Reply.RPCRequest: self._serve_rpc(embedding_map) elif self._read_type == Reply.KernelException: - self._serve_exception(embedding_map, symbolizer, demangler) + self._serve_exception(embedding_map, symbolizer) elif self._read_type == Reply.ClockFailure: raise exceptions.ClockFailure else: diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 966838572..e4781fbec 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -1,4 +1,4 @@ -import os, sys +import os, sys, tempfile, subprocess, io from numpy import int32, int64 import nac3artiq @@ -6,6 +6,7 @@ import nac3artiq from artiq.language.core import * from artiq.language import core as core_language from artiq.language.units import * +from artiq.language.embedding_map import EmbeddingMap from artiq.coredevice.comm_kernel import CommKernel, CommKernelDummy @@ -55,11 +56,12 @@ class Core: self.core = self self.comm.core = self self.compiler = nac3artiq.NAC3(target) + self.embedding_map = EmbeddingMap() def close(self): self.comm.close() - def compile(self, method, args, kwargs, file_output=None): + def compile(self, method, args, kwargs, embedding_map, file_output=None): if core_language._allow_registration: self.compiler.analyze(core_language._registered_functions, core_language._registered_classes) core_language._allow_registration = False @@ -72,18 +74,21 @@ class Core: name = "" if file_output is None: - return self.compiler.compile_method_to_mem(obj, name, args) + return self.compiler.compile_method_to_mem(obj, name, args, embedding_map) else: - self.compiler.compile_method_to_file(obj, name, args, file_output) + self.compiler.compile_method_to_file(obj, name, args, file_output, embedding_map) def run(self, function, args, kwargs): - kernel_library = self.compile(function, args, kwargs) + kernel_library = self.compile(function, args, kwargs, self.embedding_map) if self.first_run: self.comm.check_system_info() self.first_run = False + + symbolizer = lambda addresses: symbolize(kernel_library, addresses) + self.comm.load(kernel_library) self.comm.run() - self.comm.serve(None, None, None) + self.comm.serve(self.embedding_map, symbolizer) @portable def seconds_to_mu(self, seconds: float) -> int64: @@ -155,3 +160,96 @@ class Core: min_now = rtio_get_counter() + int64(125000) if now_mu() < min_now: at_mu(min_now) + + +class RunTool: + def __init__(self, pattern, **tempdata): + self._pattern = pattern + self._tempdata = tempdata + self._tempnames = {} + self._tempfiles = {} + + def __enter__(self): + for key, data in self._tempdata.items(): + if data is None: + fd, filename = tempfile.mkstemp() + os.close(fd) + self._tempnames[key] = filename + else: + with tempfile.NamedTemporaryFile(delete=False) as f: + f.write(data) + self._tempnames[key] = f.name + + cmdline = [] + for argument in self._pattern: + cmdline.append(argument.format(**self._tempnames)) + + # https://bugs.python.org/issue17023 + windows = os.name == "nt" + process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + universal_newlines=True, shell=windows) + stdout, stderr = process.communicate() + if process.returncode != 0: + raise Exception("{} invocation failed: {}". + format(cmdline[0], stderr)) + + self._tempfiles["__stdout__"] = io.StringIO(stdout) + for key in self._tempdata: + if self._tempdata[key] is None: + self._tempfiles[key] = open(self._tempnames[key], "rb") + return self._tempfiles + + def __exit__(self, exc_typ, exc_value, exc_trace): + for file in self._tempfiles.values(): + file.close() + for filename in self._tempnames.values(): + os.unlink(filename) + + +def symbolize(library, addresses): + if addresses == []: + return [] + + # We got a list of return addresses, i.e. addresses of instructions + # just after the call. Offset them back to get an address somewhere + # inside the call instruction (or its delay slot), since that's what + # the backtrace entry should point at. + last_inlined = None + offset_addresses = [hex(addr - 1) for addr in addresses] + with RunTool(["llvm-addr2line", "--addresses", "--functions", "--inlines", + "--demangle", "--exe={library}"] + offset_addresses, + library=library) \ + as results: + lines = iter(results["__stdout__"].read().rstrip().split("\n")) + backtrace = [] + while True: + try: + address_or_function = next(lines) + except StopIteration: + break + if address_or_function[:2] == "0x": + address = int(address_or_function[2:], 16) + 1 # remove offset + function = next(lines) + inlined = False + else: + address = backtrace[-1][4] # inlined + function = address_or_function + inlined = True + location = next(lines) + + filename, line = location.rsplit(":", 1) + if filename == "??" or filename == "": + continue + if line == "?": + line = -1 + else: + line = int(line) + # can't get column out of addr2line D: + if inlined: + last_inlined.append((filename, line, -1, function, address)) + else: + last_inlined = [] + backtrace.append((filename, line, -1, function, address, + last_inlined)) + return backtrace + diff --git a/artiq/frontend/artiq_compile.py b/artiq/frontend/artiq_compile.py index 95be09c9c..32218c9ec 100755 --- a/artiq/frontend/artiq_compile.py +++ b/artiq/frontend/artiq_compile.py @@ -8,6 +8,7 @@ from artiq import __version__ as artiq_version from artiq.master.databases import DeviceDB, DatasetDB from artiq.master.worker_db import DeviceManager, DatasetManager from artiq.language.environment import ProcessArgumentManager +from artiq.language.embedding_map import EmbeddingMap from artiq.tools import * @@ -46,6 +47,8 @@ def main(): device_mgr = DeviceManager(DeviceDB(args.device_db)) dataset_mgr = DatasetManager(DatasetDB(args.dataset_db)) + embedding_map = EmbeddingMap() + output = args.output if output is None: basename, ext = os.path.splitext(args.file) @@ -60,7 +63,7 @@ def main(): if not getattr(exp.run, "__artiq_kernel__", False): raise ValueError("Experiment entry point must be a kernel") - exp_inst.core.compile(exp_inst.run, [], {}, file_output=output) + exp_inst.core.compile(exp_inst.run, [], {}, embedding_map, file_output=output) finally: device_mgr.close_devices() diff --git a/artiq/language/__init__.py b/artiq/language/__init__.py index 99c019a75..145471752 100644 --- a/artiq/language/__init__.py +++ b/artiq/language/__init__.py @@ -3,6 +3,7 @@ from artiq.language.core import * from artiq.language.environment import * from artiq.language.units import * from artiq.language.scan import * +from artiq.language.embedding_map import * from . import import_cache __all__ = ["import_cache"] @@ -10,3 +11,4 @@ __all__.extend(core.__all__) __all__.extend(environment.__all__) __all__.extend(units.__all__) __all__.extend(scan.__all__) +__all__.extend(embedding_map.__all__) diff --git a/artiq/language/core.py b/artiq/language/core.py index b9f5fe8a9..b2d0f2cec 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -104,7 +104,7 @@ def rpc(arg=None, flags={}): def inner_decorator(function): return rpc(function, flags) return inner_decorator - + return arg @nac3 class KernelContextManager: diff --git a/artiq/language/embedding_map.py b/artiq/language/embedding_map.py new file mode 100644 index 000000000..87d0ab9b6 --- /dev/null +++ b/artiq/language/embedding_map.py @@ -0,0 +1,62 @@ +__all__ = [ + 'EmbeddingMap' +] + +class EmbeddingMap: + def __init__(self): + self.object_inverse_map = {} + self.object_map = {} + self.string_map = {} + self.string_reverse_map = {} + self.function_map = {} + + # preallocate exception names + self.preallocate_runtime_exception_names(["RuntimeError", + "RTIOUnderflow", + "RTIOOverflow", + "RTIODestinationUnreachable", + "DMAError", + "I2CError", + "CacheError", + "SPIError", + "0:ZeroDivisionError", + "0:IndexError"]) + + def preallocate_runtime_exception_names(self, names): + for i, name in enumerate(names): + if ":" not in name: + name = "0:artiq.coredevice.exceptions." + name + exn_id = self.store_str(name) + assert exn_id == i + + def store_function(self, key, fun): + self.function_map[key] = fun + return key + + def store_object(self, obj): + obj_id = id(obj) + if obj_id in self.object_inverse_map: + return self.object_inverse_map[obj_id] + key = len(self.object_map) + self.object_map[key] = obj + self.object_inverse_map[obj_id] = key + return key + + def store_str(self, s): + if s in self.string_reverse_map: + return self.string_reverse_map[s] + key = len(self.string_map) + self.string_map[key] = s + self.string_reverse_map[s] = key + return key + + def retrieve_function(self, key): + return self.function_map[key] + + def retrieve_object(self, key): + return self.object_map[key] + + def retrieve_str(self, key): + return self.string_map[key] + + From 92c1bc2149ea9ce3af2a8ba1e05d6cc419813b5b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 Feb 2022 11:00:23 +0800 Subject: [PATCH 068/352] core: remove legacy synthesized filename --- artiq/coredevice/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index e4781fbec..9cf9a6117 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -238,7 +238,7 @@ def symbolize(library, addresses): location = next(lines) filename, line = location.rsplit(":", 1) - if filename == "??" or filename == "": + if filename == "??": continue if line == "?": line = -1 From 4cd47fa9354862cbe325fd03af1e08e1acaa694a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 Feb 2022 12:47:37 +0800 Subject: [PATCH 069/352] update NAC3 --- flake.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/flake.lock b/flake.lock index cf8c176d3..2a3aad7d0 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1638887313, - "narHash": "sha256-FMYV6rVtvSIfthgC1sK1xugh3y7muoQcvduMdriz4ag=", + "lastModified": 1643634764, + "narHash": "sha256-EcFlgzZnZSHwZixELYV1pa267t+u5mCeLhSNBeAA/+c=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "7c1e8b1dd6ed0043fb4ee0b12b815256b0b9de6f", + "rev": "f233fdc4ff6ba2ffeb1e3e3cd6d63bb1297d6996", "type": "github" }, "original": { @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1642522226, - "narHash": "sha256-m/j9U8KYuwwxjwgRCjmEj8ejftvdMLJ+NGXh/L2I4FU=", + "lastModified": 1644472683, + "narHash": "sha256-sP6iM4NksOYO6NFfTJ96cg+ClPnq6cdY30xKA1iYtyU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "610d4ea2750e064bf34b33fa38cb671edd893d3d", + "rev": "7adc9c14ec74b27358a8df9b973087e351425a79", "type": "github" }, "original": { @@ -80,11 +80,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1643140707, - "narHash": "sha256-sCfXT/4ozkYfR7HxvHrq65CKaSUpaJ3NGVoYMA8YyMc=", + "lastModified": 1644723702, + "narHash": "sha256-2pLJHYvQmoXhdy3WDZpfU7kDMpgH/G7uREZOyql7R10=", "ref": "master", - "rev": "43048eb8d8273a7c17bb216623482b60649547b0", - "revCount": 567, + "rev": "4b8e70f7462b139e388f098d42f9f47e4915f431", + "revCount": 589, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, @@ -96,11 +96,11 @@ "src-sipyco": { "flake": false, "locked": { - "lastModified": 1641866796, - "narHash": "sha256-TSH0IgNbi9IcMcBDb2nWRphKlxstbWeATjrGbi6K2m0=", + "lastModified": 1644649772, + "narHash": "sha256-LE9L5bDSunCPEnuf5Ed8enTAXA2vkTSmjvqPX9ILO0Y=", "owner": "m-labs", "repo": "sipyco", - "rev": "b04234c49379cd446d4cb3346d4741868d86841a", + "rev": "8e4382352bc64bd01c9db35d9c9b0ef42b8b9d3b", "type": "github" }, "original": { From 2616e1928d9f9629010dd36db8a6e0accc28bab9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 Feb 2022 12:47:53 +0800 Subject: [PATCH 070/352] ttl: fix type error --- artiq/coredevice/ttl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 9143dc7c9..b7cf4fe99 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -447,7 +447,7 @@ class TTLInOut: rtio_output(self.target_sens, 0) success = True try: - while rtio_input_timestamp(now_mu() + int64(self.gate_latency_mu), self.channel) != -1: + while rtio_input_timestamp(now_mu() + int64(self.gate_latency_mu), self.channel) != int64(-1): success = False except RTIOOverflow: success = False From e8e1ccd4f1ba37ed32030dedb376dc93fe4784c5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 Feb 2022 12:49:09 +0800 Subject: [PATCH 071/352] coredevice/exceptions: port to NAC3 --- artiq/coredevice/comm_kernel.py | 96 ++++++++++++++++++ artiq/coredevice/exceptions.py | 173 +++++++------------------------- 2 files changed, 132 insertions(+), 137 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 3f9c70cdc..e44327887 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -3,6 +3,8 @@ import logging import traceback import numpy import socket +import re +import linecache from enum import Enum from fractions import Fraction from collections import namedtuple @@ -10,6 +12,8 @@ from collections import namedtuple from artiq.coredevice import exceptions from artiq.coredevice.comm import initialize_connection from artiq import __version__ as software_version +from artiq.coredevice.runtime import source_loader +from artiq import __artiq_dir__ as artiq_dir logger = logging.getLogger(__name__) @@ -171,6 +175,98 @@ class CommKernelDummy: pass + +class CoreException: + """Information about an exception raised or passed through the core device.""" + def __init__(self, exceptions, exception_info, traceback, stack_pointers): + self.exceptions = exceptions + self.exception_info = exception_info + self.traceback = list(traceback) + self.stack_pointers = stack_pointers + + first_exception = exceptions[0] + name = first_exception[0] + if ':' in name: + exn_id, self.name = name.split(':', 2) + self.id = int(exn_id) + else: + self.id, self.name = 0, name + self.message = first_exception[1] + self.params = first_exception[2] + + def append_backtrace(self, record, inlined=False): + filename, line, column, function, address = record + stub_globals = {"__name__": filename, "__loader__": source_loader} + source_line = linecache.getline(filename, line, stub_globals) + indentation = re.search(r"^\s*", source_line).end() + + if address is None: + formatted_address = "" + elif inlined: + formatted_address = " (inlined)" + else: + formatted_address = " (RA=+0x{:x})".format(address) + + filename = filename.replace(artiq_dir, "") + lines = [] + if column == -1: + lines.append(" {}".format(source_line.strip() if source_line else "")) + lines.append(" File \"{file}\", line {line}, in {function}{address}". + format(file=filename, line=line, function=function, + address=formatted_address)) + else: + lines.append(" {}^".format(" " * (column - indentation))) + lines.append(" {}".format(source_line.strip() if source_line else "")) + lines.append(" File \"{file}\", line {line}, column {column}," + " in {function}{address}". + format(file=filename, line=line, column=column + 1, + function=function, address=formatted_address)) + return lines + + def single_traceback(self, exception_index): + # note that we insert in reversed order + lines = [] + last_sp = 0 + start_backtrace_index = self.exception_info[exception_index][1] + zipped = list(zip(self.traceback[start_backtrace_index:], + self.stack_pointers[start_backtrace_index:])) + exception = self.exceptions[exception_index] + name = exception[0] + message = exception[1] + params = exception[2] + if ':' in name: + exn_id, name = name.split(':', 2) + exn_id = int(exn_id) + else: + exn_id = 0 + lines.append("{}({}): {}".format(name, exn_id, message.format(*params))) + zipped.append(((exception[3], exception[4], exception[5], exception[6], + None, []), None)) + + for ((filename, line, column, function, address, inlined), sp) in zipped: + # backtrace of nested exceptions may be discontinuous + # but the stack pointer must increase monotonically + if sp is not None and sp <= last_sp: + continue + last_sp = sp + + for record in reversed(inlined): + lines += self.append_backtrace(record, True) + lines += self.append_backtrace((filename, line, column, function, + address)) + + lines.append("Traceback (most recent call first):") + + return "\n".join(reversed(lines)) + + def __str__(self): + tracebacks = [self.single_traceback(i) for i in range(len(self.exceptions))] + traceback_str = ('\n\nDuring handling of the above exception, ' + + 'another exception occurred:\n\n').join(tracebacks) + return 'Core Device Traceback:\n' +\ + traceback_str +\ + '\n\nEnd of Core Device Traceback\n' + class CommKernel: warned_of_mismatch = False diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 9600bdd29..c64e4960d 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -1,162 +1,61 @@ -import builtins -import linecache -import re -import os - -from artiq import __artiq_dir__ as artiq_dir -from artiq.coredevice.runtime import source_loader - - -ZeroDivisionError = builtins.ZeroDivisionError -ValueError = builtins.ValueError -IndexError = builtins.IndexError -RuntimeError = builtins.RuntimeError -AssertionError = builtins.AssertionError - - -class CoreException: - """Information about an exception raised or passed through the core device.""" - def __init__(self, exceptions, exception_info, traceback, stack_pointers): - self.exceptions = exceptions - self.exception_info = exception_info - self.traceback = list(traceback) - self.stack_pointers = stack_pointers - - first_exception = exceptions[0] - name = first_exception[0] - if ':' in name: - exn_id, self.name = name.split(':', 2) - self.id = int(exn_id) - else: - self.id, self.name = 0, name - self.message = first_exception[1] - self.params = first_exception[2] - - def append_backtrace(self, record, inlined=False): - filename, line, column, function, address = record - stub_globals = {"__name__": filename, "__loader__": source_loader} - source_line = linecache.getline(filename, line, stub_globals) - indentation = re.search(r"^\s*", source_line).end() - - if address is None: - formatted_address = "" - elif inlined: - formatted_address = " (inlined)" - else: - formatted_address = " (RA=+0x{:x})".format(address) - - filename = filename.replace(artiq_dir, "") - lines = [] - if column == -1: - lines.append(" {}".format(source_line.strip() if source_line else "")) - lines.append(" File \"{file}\", line {line}, in {function}{address}". - format(file=filename, line=line, function=function, - address=formatted_address)) - else: - lines.append(" {}^".format(" " * (column - indentation))) - lines.append(" {}".format(source_line.strip() if source_line else "")) - lines.append(" File \"{file}\", line {line}, column {column}," - " in {function}{address}". - format(file=filename, line=line, column=column + 1, - function=function, address=formatted_address)) - return lines - - def single_traceback(self, exception_index): - # note that we insert in reversed order - lines = [] - last_sp = 0 - start_backtrace_index = self.exception_info[exception_index][1] - zipped = list(zip(self.traceback[start_backtrace_index:], - self.stack_pointers[start_backtrace_index:])) - exception = self.exceptions[exception_index] - name = exception[0] - message = exception[1] - params = exception[2] - if ':' in name: - exn_id, name = name.split(':', 2) - exn_id = int(exn_id) - else: - exn_id = 0 - lines.append("{}({}): {}".format(name, exn_id, message.format(*params))) - zipped.append(((exception[3], exception[4], exception[5], exception[6], - None, []), None)) - - for ((filename, line, column, function, address, inlined), sp) in zipped: - # backtrace of nested exceptions may be discontinuous - # but the stack pointer must increase monotonically - if sp is not None and sp <= last_sp: - continue - last_sp = sp - - for record in reversed(inlined): - lines += self.append_backtrace(record, True) - lines += self.append_backtrace((filename, line, column, function, - address)) - - lines.append("Traceback (most recent call first):") - - return "\n".join(reversed(lines)) - - def __str__(self): - tracebacks = [self.single_traceback(i) for i in range(len(self.exceptions))] - traceback_str = ('\n\nDuring handling of the above exception, ' + - 'another exception occurred:\n\n').join(tracebacks) - return 'Core Device Traceback:\n' +\ - traceback_str +\ - '\n\nEnd of Code Device Traceback\n' - - -class InternalError(Exception): - """Raised when the runtime encounters an internal error condition.""" - artiq_builtin = True - - -class CacheError(Exception): - """Raised when putting a value into a cache row would violate memory safety.""" - artiq_builtin = True +from artiq.language.core import nac3 +@nac3 class RTIOUnderflow(Exception): - """Raised when the CPU or DMA core fails to submit a RTIO event early - enough (with respect to the event's timestamp). + # NAC3TODO """Raised when the CPU or DMA core fails to submit a RTIO event early + # enough (with respect to the event's timestamp). - The offending event is discarded and the RTIO core keeps operating. - """ - artiq_builtin = True + # The offending event is discarded and the RTIO core keeps operating. + # """ + pass +@nac3 class RTIOOverflow(Exception): - """Raised when at least one event could not be registered into the RTIO - input FIFO because it was full (CPU not reading fast enough). + # NAC3TODO """Raised when at least one event could not be registered into the RTIO + # input FIFO because it was full (CPU not reading fast enough). - This does not interrupt operations further than cancelling the current - read attempt and discarding some events. Reading can be reattempted after - the exception is caught, and events will be partially retrieved. - """ - artiq_builtin = True + # This does not interrupt operations further than cancelling the current + # read attempt and discarding some events. Reading can be reattempted after + # the exception is caught, and events will be partially retrieved. + # """ + pass +@nac3 class RTIODestinationUnreachable(Exception): - """Raised with a RTIO operation could not be completed due to a DRTIO link - being down. - """ - artiq_builtin = True + # NAC3TODO """Raised with a RTIO operation could not be completed due to a DRTIO link + # being down. + # """ + pass +@nac3 +class CacheError(Exception): + # NAC3TODO """Raised when putting a value into a cache row would violate memory safety.""" + pass + + +@nac3 class DMAError(Exception): - """Raised when performing an invalid DMA operation.""" - artiq_builtin = True + # NAC3TODO """Raised when performing an invalid DMA operation.""" + pass +@nac3 class ClockFailure(Exception): - """Raised when RTIO PLL has lost lock.""" + # NAC3TODO """Raised when RTIO PLL has lost lock.""" + pass +@nac3 class I2CError(Exception): - """Raised when a I2C transaction fails.""" + # NAC3TODO """Raised when a I2C transaction fails.""" pass +@nac3 class SPIError(Exception): - """Raised when a SPI transaction fails.""" + # NAC3TODO """Raised when a SPI transaction fails.""" pass From 207ff918c7394bf55476063d4f5af81a94dff9ff Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 Feb 2022 12:50:22 +0800 Subject: [PATCH 072/352] coredevice: define ValueError locally work around https://git.m-labs.hk/M-Labs/nac3/issues/189 --- artiq/coredevice/ad53xx.py | 6 ++++++ artiq/coredevice/ad9912.py | 6 ++++++ artiq/coredevice/adf5356.py | 6 ++++++ artiq/coredevice/mirny.py | 6 ++++++ artiq/coredevice/spi2.py | 7 +++++++ artiq/coredevice/urukul.py | 7 +++++++ 6 files changed, 38 insertions(+) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 0abfd76d9..f09323cc5 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -17,6 +17,12 @@ from artiq.coredevice.ttl import TTLOut from artiq.coredevice.spi2 import * +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass + + SPI_AD53XX_CONFIG = (0*SPI_OFFLINE | 1*SPI_END | 0*SPI_INPUT | 0*SPI_CS_POLARITY | 0*SPI_CLK_POLARITY | 1*SPI_CLK_PHASE | diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index c11b295c2..e563fb823 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -10,6 +10,12 @@ from artiq.coredevice.urukul import * from artiq.coredevice.ttl import TTLOut +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass + + @nac3 class AD9912: """ diff --git a/artiq/coredevice/adf5356.py b/artiq/coredevice/adf5356.py index e783c8088..bb02ee8ba 100644 --- a/artiq/coredevice/adf5356.py +++ b/artiq/coredevice/adf5356.py @@ -20,6 +20,12 @@ from artiq.coredevice.spi2 import * from artiq.coredevice.adf5356_reg import * +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass + + SPI_CONFIG = ( 0 * SPI_OFFLINE diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py index 9a87dc936..ea18ef881 100644 --- a/artiq/coredevice/mirny.py +++ b/artiq/coredevice/mirny.py @@ -10,6 +10,12 @@ from artiq.coredevice.core import Core from artiq.coredevice.spi2 import * +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass + + SPI_CONFIG = ( 0 * SPI_OFFLINE | 0 * SPI_END diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index 3b0147a6a..657cb4cf8 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -14,6 +14,13 @@ from artiq.coredevice.core import Core from artiq.coredevice.rtio import rtio_output, rtio_input_data +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass + + + __all__ = [ "SPI_DATA_ADDR", "SPI_CONFIG_ADDR", "SPI_OFFLINE", "SPI_END", "SPI_INPUT", diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index f2796a581..ed20b962b 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -8,6 +8,13 @@ from artiq.coredevice.spi2 import * from artiq.coredevice.ttl import TTLOut +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass + + + SPI_CONFIG = (0 * SPI_OFFLINE | 0 * SPI_END | 0 * SPI_INPUT | 1 * SPI_CS_POLARITY | 0 * SPI_CLK_POLARITY | 0 * SPI_CLK_PHASE | From 8aa8647ba8d2f7b64ac827d7e209dd1dec11ec6a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 Feb 2022 12:51:23 +0800 Subject: [PATCH 073/352] coredevice: use NAC3 exception support --- artiq/coredevice/ad53xx.py | 12 ++++-------- artiq/coredevice/ad9912.py | 3 +-- artiq/coredevice/adf5356.py | 18 ++++++------------ artiq/coredevice/mirny.py | 6 ++---- artiq/coredevice/spi2.py | 9 ++++----- artiq/coredevice/ttl.py | 2 +- artiq/coredevice/urukul.py | 6 ++---- 7 files changed, 20 insertions(+), 36 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index f09323cc5..080713090 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -110,8 +110,7 @@ def voltage_to_mu(voltage: float, offset_dacs: int32 = 0x2000, vref: float = 5.) """ code = round(float(1 << 16) * (voltage / (4. * vref))) + offset_dacs * 0x4 if code < 0x0 or code > 0xffff: - # NAC3TODO raise ValueError("Invalid DAC voltage!") - pass + raise ValueError("Invalid DAC voltage!") return code @@ -197,19 +196,16 @@ class AD53xx: if not blind: ctrl = self.read_reg(0, AD53XX_READ_CONTROL) if ctrl == 0xffff: - # NAC3TODO raise ValueError("DAC not found") - pass + raise ValueError("DAC not found") if (ctrl & 0b10000) != 0: - # NAC3TODO raise ValueError("DAC over temperature") - pass + raise ValueError("DAC over temperature") self.core.delay(25.*us) self.bus.write( # enable power and overtemperature shutdown (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_CONTROL | 0b0010) << 8) if not blind: ctrl = self.read_reg(0, AD53XX_READ_CONTROL) if (ctrl & 0b10111) != 0b00010: - # NAC3TODO raise ValueError("DAC CONTROL readback mismatch") - pass + raise ValueError("DAC CONTROL readback mismatch") self.core.delay(15.*us) @kernel diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index e563fb823..ae7bb2bd6 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -112,8 +112,7 @@ class AD9912: # Verify chip ID and presence prodid = self.read(AD9912_PRODIDH, 2) if (prodid != 0x1982) and (prodid != 0x1902): - # NAC3TODO raise ValueError("Urukul AD9912 product id mismatch") - pass + raise ValueError() # NAC3TODO("Urukul AD9912 product id mismatch") self.core.delay(50. * us) # HSTL power down, CMOS power down self.write(AD9912_PWRCNTRL1, 0x80, 1) diff --git a/artiq/coredevice/adf5356.py b/artiq/coredevice/adf5356.py index bb02ee8ba..f7020cd7b 100644 --- a/artiq/coredevice/adf5356.py +++ b/artiq/coredevice/adf5356.py @@ -103,8 +103,7 @@ class ADF5356: self.sync() self.core.delay(1000. * us) if not self.read_muxout(): - # NAC3TODO raise ValueError("MUXOUT not high") - pass + raise ValueError("MUXOUT not high") self.core.delay(800. * us) # MUXOUT = DGND @@ -112,8 +111,7 @@ class ADF5356: self.sync() self.core.delay(1000. * us) if self.read_muxout(): - # NAC3TODO raise ValueError("MUXOUT not low") - pass + raise ValueError("MUXOUT not low") self.core.delay(800. * us) # MUXOUT = digital lock-detect @@ -152,8 +150,7 @@ class ADF5356: :param n: output power setting, 0, 1, 2, or 3 (see ADF5356 datasheet, fig. 44). """ if not 0 <= n <= 3: - # NAC3TODO raise ValueError("invalid power setting") - pass + raise ValueError("invalid power setting") self.regs[6] = ADF5356_REG6_RF_OUTPUT_A_POWER_UPDATE(self.regs[6], n) self.sync() @@ -190,8 +187,7 @@ class ADF5356: freq = round64(f) if freq > ADF5356_MAX_VCO_FREQ: - # NAC3TODO raise ValueError("Requested too high frequency") - pass + raise ValueError("Requested too high frequency") # select minimal output divider rf_div_sel = 0 @@ -200,8 +196,7 @@ class ADF5356: rf_div_sel += 1 if (1 << rf_div_sel) > 64: - # NAC3TODO raise ValueError("Requested too low frequency") - pass + raise ValueError("Requested too low frequency") # choose reference divider that maximizes PFD frequency self.regs[4] = ADF5356_REG4_R_COUNTER_UPDATE( @@ -229,8 +224,7 @@ class ADF5356: ) if not (n_min <= n <= n_max): - # NAC3TODO raise ValueError("Invalid INT value") - pass + raise ValueError("Invalid INT value") # configure PLL self.regs[0] = ADF5356_REG0_INT_VALUE_UPDATE(self.regs[0], n) diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py index ea18ef881..2a8210c30 100644 --- a/artiq/coredevice/mirny.py +++ b/artiq/coredevice/mirny.py @@ -132,16 +132,14 @@ class Mirny: if not blind: if (reg0 >> 2) & 0x3 != PROTO_REV_MATCH: - # NAC3TODO raise ValueError("Mirny PROTO_REV mismatch") - pass + raise ValueError("Mirny PROTO_REV mismatch") self.core.delay(100. * us) # slack # select clock source self.clk_sel = self.clk_sel_hw_rev[self.hw_rev] if self.clk_sel < 0: - # NAC3TODO raise ValueError("Hardware revision not supported") - pass + raise ValueError("Hardware revision not supported") self.write_reg(1, (self.clk_sel << 4)) self.core.delay(1000. * us) diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index 657cb4cf8..19e5ce805 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -174,11 +174,10 @@ class SPIMaster: Or number of the chip select to assert if ``cs`` is decoded downstream. (reset=0) """ - # NAC3TODO - #if length > 32 or length < 1: - # raise ValueError("Invalid SPI transfer length") - #if div > 257 or div < 2: - # raise ValueError("Invalid SPI clock divider") + if length > 32 or length < 1: + raise ValueError("Invalid SPI transfer length") + if div > 257 or div < 2: + raise ValueError("Invalid SPI clock divider") rtio_output((self.channel << 8) | SPI_CONFIG_ADDR, flags | ((length - 1) << 8) | ((div - 2) << 16) | (cs << 24)) self.update_xfer_duration_mu(div, length) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index b7cf4fe99..795c0fbe0 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -434,7 +434,7 @@ class TTLInOut: rtio_output(self.target_sample, 1) # gate rising return rtio_input_data(self.channel) == 0 - # NAC3TODO @kernel + @kernel def watch_done(self) -> bool: """Stop watching the input at the position of the time cursor. diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index ed20b962b..18cc5c9d1 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -260,8 +260,7 @@ class CPLD: else: proto_rev = urukul_sta_proto_rev(self.sta_read()) if proto_rev != STA_PROTO_REV_MATCH: - # NAC3TODO raise ValueError("Urukul proto_rev mismatch") - pass + raise ValueError("Urukul proto_rev mismatch") self.core.delay(100. * us) # reset, slack self.cfg_write(cfg) if self.sync_div != 0: @@ -317,8 +316,7 @@ class CPLD: """ code = 255 - round(att * 8.) if code < 0 or code > 255: - # NAC3TODO raise ValueError("Invalid urukul.CPLD attenuation!") - pass + raise ValueError("Invalid urukul.CPLD attenuation!") return code @kernel From 8e1ac8b844fdaa787be2d0a3f33fb4acef5debe2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 Feb 2022 13:32:20 +0800 Subject: [PATCH 074/352] Revert "core: remove legacy synthesized filename" This reverts commit 92c1bc2149ea9ce3af2a8ba1e05d6cc419813b5b. --- artiq/coredevice/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 9cf9a6117..e4781fbec 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -238,7 +238,7 @@ def symbolize(library, addresses): location = next(lines) filename, line = location.rsplit(":", 1) - if filename == "??": + if filename == "??" or filename == "": continue if line == "?": line = -1 From 9f620491a9808b449629100d4d10681f4691bb4e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 Feb 2022 13:32:50 +0800 Subject: [PATCH 075/352] coredevice: fix exception return handling --- artiq/coredevice/comm_kernel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index e44327887..9e5711bf6 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -758,7 +758,7 @@ class CommKernel: self._process_async_error() traceback = list(symbolizer(backtrace)) - core_exn = exceptions.CoreException(nested_exceptions, exception_info, + core_exn = CoreException(nested_exceptions, exception_info, traceback, stack_pointers) if core_exn.id == 0: From ec6c6dd988737d8d6817e4ac205a4e693b8d2ecf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 Feb 2022 13:48:05 +0800 Subject: [PATCH 076/352] add comments about preallocate_runtime_exception_names/EXCEPTION_ID_LOOKUP syncing --- artiq/firmware/ksupport/eh_artiq.rs | 1 + artiq/language/embedding_map.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/artiq/firmware/ksupport/eh_artiq.rs b/artiq/firmware/ksupport/eh_artiq.rs index 30e173dc0..e782f783c 100644 --- a/artiq/firmware/ksupport/eh_artiq.rs +++ b/artiq/firmware/ksupport/eh_artiq.rs @@ -333,6 +333,7 @@ extern fn stop_fn(_version: c_int, } } +// Must be kept in sync with preallocate_runtime_exception_names() in artiq/language/embedding_map.py static EXCEPTION_ID_LOOKUP: [(&str, u32); 10] = [ ("RuntimeError", 0), ("RTIOUnderflow", 1), diff --git a/artiq/language/embedding_map.py b/artiq/language/embedding_map.py index 87d0ab9b6..3ff224b67 100644 --- a/artiq/language/embedding_map.py +++ b/artiq/language/embedding_map.py @@ -11,6 +11,8 @@ class EmbeddingMap: self.function_map = {} # preallocate exception names + # must be kept in sync with EXCEPTION_ID_LOOKUP in artiq/firmware/ksupport/eh_artiq.rs, + # and src/runtime/src/eh_artiq.rs (Zynq) self.preallocate_runtime_exception_names(["RuntimeError", "RTIOUnderflow", "RTIOOverflow", From e76df491f244a15f12302b43899fb62b8d40e670 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 14 Feb 2022 16:39:26 +0800 Subject: [PATCH 077/352] coredevice/exceptions: nac3 no longer breaks because of docstrings --- artiq/coredevice/exceptions.py | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index c64e4960d..5f50b1372 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -3,59 +3,59 @@ from artiq.language.core import nac3 @nac3 class RTIOUnderflow(Exception): - # NAC3TODO """Raised when the CPU or DMA core fails to submit a RTIO event early - # enough (with respect to the event's timestamp). + """Raised when the CPU or DMA core fails to submit a RTIO event early + enough (with respect to the event's timestamp). - # The offending event is discarded and the RTIO core keeps operating. - # """ + The offending event is discarded and the RTIO core keeps operating. + """ pass @nac3 class RTIOOverflow(Exception): - # NAC3TODO """Raised when at least one event could not be registered into the RTIO - # input FIFO because it was full (CPU not reading fast enough). + """Raised when at least one event could not be registered into the RTIO + input FIFO because it was full (CPU not reading fast enough). - # This does not interrupt operations further than cancelling the current - # read attempt and discarding some events. Reading can be reattempted after - # the exception is caught, and events will be partially retrieved. - # """ + This does not interrupt operations further than cancelling the current + read attempt and discarding some events. Reading can be reattempted after + the exception is caught, and events will be partially retrieved. + """ pass @nac3 class RTIODestinationUnreachable(Exception): - # NAC3TODO """Raised with a RTIO operation could not be completed due to a DRTIO link - # being down. - # """ + """Raised with a RTIO operation could not be completed due to a DRTIO link + being down. + """ pass @nac3 class CacheError(Exception): - # NAC3TODO """Raised when putting a value into a cache row would violate memory safety.""" + """Raised when putting a value into a cache row would violate memory safety.""" pass @nac3 class DMAError(Exception): - # NAC3TODO """Raised when performing an invalid DMA operation.""" + """Raised when performing an invalid DMA operation.""" pass @nac3 class ClockFailure(Exception): - # NAC3TODO """Raised when RTIO PLL has lost lock.""" + """Raised when RTIO PLL has lost lock.""" pass @nac3 class I2CError(Exception): - # NAC3TODO """Raised when a I2C transaction fails.""" + """Raised when a I2C transaction fails.""" pass @nac3 class SPIError(Exception): - # NAC3TODO """Raised when a SPI transaction fails.""" + """Raised when a SPI transaction fails.""" pass From 9ab740d0048bfe510fe50d8065449772c56939a7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 23 Feb 2022 11:07:20 +0800 Subject: [PATCH 078/352] update nac3 and dependencies --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 1ae195f8e..2249a5c6a 100644 --- a/flake.lock +++ b/flake.lock @@ -27,11 +27,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1643634764, - "narHash": "sha256-EcFlgzZnZSHwZixELYV1pa267t+u5mCeLhSNBeAA/+c=", + "lastModified": 1645464064, + "narHash": "sha256-YeN4bpPvHkVOpQzb8APTAfE7/R+MFMwJUMkqmfvytSk=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "f233fdc4ff6ba2ffeb1e3e3cd6d63bb1297d6996", + "rev": "15b7a05f20aab51c4ffbefddb1b448e862dccb7d", "type": "github" }, "original": { @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1644759922, - "narHash": "sha256-3hNFahCeHp0seppVONSlAMXIzn0vjCJGrJj6CySLLxw=", + "lastModified": 1645585475, + "narHash": "sha256-5WMX0ySH6uSRaaYw3wmjN/xFmStsUJUR8Ln1+08mwec=", "ref": "master", - "rev": "21d9182ba2924cf9cc555a201e661d2ea474eed9", - "revCount": 594, + "rev": "17792b76b7879450cc37db8968fa71fb5ab67941", + "revCount": 603, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, @@ -60,11 +60,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1644472683, - "narHash": "sha256-sP6iM4NksOYO6NFfTJ96cg+ClPnq6cdY30xKA1iYtyU=", + "lastModified": 1645379616, + "narHash": "sha256-eLzR3MRS9hcNqSWZxP6BP7xiBjgC3/pB5n2Q0lLFe/g=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7adc9c14ec74b27358a8df9b973087e351425a79", + "rev": "40ef692a55b188b1f5ae3967f3fc7808838c3f1d", "type": "github" }, "original": { From e3a2825ae7256708ad1c967bafb09b492b007a84 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 23 Feb 2022 11:41:11 +0800 Subject: [PATCH 079/352] update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 2249a5c6a..e8819b1a3 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1645585475, - "narHash": "sha256-5WMX0ySH6uSRaaYw3wmjN/xFmStsUJUR8Ln1+08mwec=", + "lastModified": 1645782167, + "narHash": "sha256-gLYGR0bFqKrzIErn3TLSpliUjfrzZoepuXwBEA5ov7E=", "ref": "master", - "rev": "17792b76b7879450cc37db8968fa71fb5ab67941", - "revCount": 603, + "rev": "e710b6c320e2da12ff8f40f9de66538a3083b2f6", + "revCount": 608, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 464818da34eca74a1be46f19939501490d7dc26e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 25 Feb 2022 18:26:01 +0800 Subject: [PATCH 080/352] ad9912: exception with string is supported by nac3 --- artiq/coredevice/ad9912.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index ae7bb2bd6..317670e52 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -112,7 +112,7 @@ class AD9912: # Verify chip ID and presence prodid = self.read(AD9912_PRODIDH, 2) if (prodid != 0x1982) and (prodid != 0x1902): - raise ValueError() # NAC3TODO("Urukul AD9912 product id mismatch") + raise ValueError("Urukul AD9912 product id mismatch") self.core.delay(50. * us) # HSTL power down, CMOS power down self.write(AD9912_PWRCNTRL1, 0x80, 1) From 3d66a6be5dbd3539a808d430f14464c19a0b0207 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 25 Feb 2022 18:26:18 +0800 Subject: [PATCH 081/352] sampler: port to nac3 --- artiq/coredevice/sampler.py | 66 +++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/artiq/coredevice/sampler.py b/artiq/coredevice/sampler.py index 8679ad93c..2722d12cf 100644 --- a/artiq/coredevice/sampler.py +++ b/artiq/coredevice/sampler.py @@ -1,13 +1,24 @@ -from artiq.language.core import kernel, delay, portable +from numpy import int32 + +from artiq.language.core import nac3, kernel, portable, Kernel, KernelInvariant from artiq.language.units import ns -from artiq.coredevice import spi2 as spi +from artiq.coredevice.core import Core +from artiq.coredevice.spi2 import * +from artiq.coredevice.ttl import TTLOut -SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | - 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass + + + +SPI_CONFIG = (0*SPI_OFFLINE | 0*SPI_END | + 0*SPI_INPUT | 0*SPI_CS_POLARITY | + 0*SPI_CLK_POLARITY | 0*SPI_CLK_PHASE | + 0*SPI_LSB_FIRST | 0*SPI_HALF_DUPLEX) SPI_CS_ADC = 0 # no CS, SPI_END does not matter, framing is done with CNV @@ -15,26 +26,28 @@ SPI_CS_PGIA = 1 # separate SPI bus, CS used as RCLK @portable -def adc_mu_to_volt(data, gain=0): +def adc_mu_to_volt(data: int32, gain: int32 = 0) -> float: """Convert ADC data in machine units to Volts. :param data: 16 bit signed ADC word :param gain: PGIA gain setting (0: 1, ..., 3: 1000) :return: Voltage in Volts """ + volt_per_lsb = 0. if gain == 0: - volt_per_lsb = 20./(1 << 16) + volt_per_lsb = 20./float(1 << 16) elif gain == 1: - volt_per_lsb = 2./(1 << 16) + volt_per_lsb = 2./float(1 << 16) elif gain == 2: - volt_per_lsb = .2/(1 << 16) + volt_per_lsb = .2/float(1 << 16) elif gain == 3: - volt_per_lsb = .02/(1 << 16) + volt_per_lsb = .02/float(1 << 16) else: raise ValueError("invalid gain") - return data*volt_per_lsb + return float(data)*volt_per_lsb +@nac3 class Sampler: """Sampler ADC. @@ -50,7 +63,12 @@ class Sampler: between experiments. :param core_device: Core device name """ - kernel_invariants = {"bus_adc", "bus_pgia", "core", "cnv", "div"} + core: KernelInvariant[Core] + bus_adc: KernelInvariant[SPIMaster] + bus_pgia: KernelInvariant[SPIMaster] + cnv: KernelInvariant[TTLOut] + div: KernelInvariant[int32] + gains: Kernel[int32] def __init__(self, dmgr, spi_adc_device, spi_pgia_device, cnv_device, div=8, gains=0x0000, core_device="core"): @@ -69,13 +87,13 @@ class Sampler: Sets up SPI channels. """ - self.bus_adc.set_config_mu(SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, + self.bus_adc.set_config_mu(SPI_CONFIG | SPI_INPUT | SPI_END, 32, self.div, SPI_CS_ADC) - self.bus_pgia.set_config_mu(SPI_CONFIG | spi.SPI_END, + self.bus_pgia.set_config_mu(SPI_CONFIG | SPI_END, 16, self.div, SPI_CS_PGIA) @kernel - def set_gain_mu(self, channel, gain): + def set_gain_mu(self, channel: int32, gain: int32): """Set instrumentation amplifier gain of a channel. The four gain settings (0, 1, 2, 3) corresponds to gains of @@ -91,21 +109,21 @@ class Sampler: self.gains = gains @kernel - def get_gains_mu(self): + def get_gains_mu(self) -> int32: """Read the PGIA gain settings of all channels. :return: The PGIA gain settings in machine units. """ - self.bus_pgia.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, + self.bus_pgia.set_config_mu(SPI_CONFIG | SPI_END | SPI_INPUT, 16, self.div, SPI_CS_PGIA) self.bus_pgia.write(self.gains << 16) - self.bus_pgia.set_config_mu(SPI_CONFIG | spi.SPI_END, + self.bus_pgia.set_config_mu(SPI_CONFIG | SPI_END, 16, self.div, SPI_CS_PGIA) self.gains = self.bus_pgia.read() & 0xffff return self.gains @kernel - def sample_mu(self, data): + def sample_mu(self, data: list[int32]): """Acquire a set of samples. Perform a conversion and transfer the samples. @@ -119,8 +137,8 @@ class Sampler: The `data` list will always be filled with the last item holding to the sample from channel 7. """ - self.cnv.pulse(30*ns) # t_CNVH - delay(450*ns) # t_CONV + self.cnv.pulse(30.*ns) # t_CNVH + self.core.delay(450.*ns) # t_CONV mask = 1 << 15 for i in range(len(data)//2): self.bus_adc.write(0) @@ -131,7 +149,7 @@ class Sampler: data[i - 1] = -(val & mask) + (val & ~mask) @kernel - def sample(self, data): + def sample(self, data: list[float]): """Acquire a set of samples. .. seealso:: :meth:`sample_mu` @@ -139,7 +157,7 @@ class Sampler: :param data: List of floating point data samples to fill. """ n = len(data) - adc_data = [0]*n + adc_data = [0 for _ in range(n)] self.sample_mu(adc_data) for i in range(n): channel = i + 8 - len(data) From 808f968617718823d7a3c0be09777addd2cf290c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 25 Feb 2022 18:27:40 +0800 Subject: [PATCH 082/352] examples/nac3devices: add sampler --- artiq/examples/nac3devices/nac3devices.json | 4 ++++ artiq/examples/nac3devices/nac3devices.py | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json index 99971df10..e57ec9fd7 100644 --- a/artiq/examples/nac3devices/nac3devices.json +++ b/artiq/examples/nac3devices/nac3devices.json @@ -21,6 +21,10 @@ "dds": "ad9912", "ports": [2, 3], "clk_sel": 2 + }, + { + "type": "sampler", + "ports": [4] } ] } diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index e01313428..7a2943e18 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -5,6 +5,7 @@ from artiq.coredevice.mirny import Mirny as MirnyCPLD from artiq.coredevice.adf5356 import ADF5356 from artiq.coredevice.urukul import CPLD as UrukulCPLD from artiq.coredevice.ad9912 import AD9912 +from artiq.coredevice.sampler import Sampler @nac3 @@ -15,6 +16,7 @@ class NAC3Devices(EnvExperiment): mirny0_ch0: KernelInvariant[ADF5356] urukul0_cpld: KernelInvariant[UrukulCPLD] urukul0_ch0: KernelInvariant[AD9912] + sampler0: KernelInvariant[Sampler] def build(self): self.setattr_device("core") @@ -23,6 +25,7 @@ class NAC3Devices(EnvExperiment): self.setattr_device("mirny0_ch0") self.setattr_device("urukul0_cpld") self.setattr_device("urukul0_ch0") + self.setattr_device("sampler0") @kernel def run(self): @@ -46,3 +49,8 @@ class NAC3Devices(EnvExperiment): self.urukul0_ch0.set((10. + float(i))*MHz) self.urukul0_ch0.set_att(6.) self.core.delay(500.*ms) + + self.core.break_realtime() + self.sampler0.init() + samples = [0. for _ in range(8)] + self.sampler0.sample(samples) From 41c597a7078f32c3547cb51d77d738516c9c586b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 25 Feb 2022 20:02:36 +0800 Subject: [PATCH 083/352] remove parts that won't initially be supported by nac3 --- artiq/coredevice/ad9154_reg.py | 2996 ----------------- artiq/coredevice/ad9154_spi.py | 23 - artiq/coredevice/basemod_att.py | 79 - .../coredevice/coredevice_generic.schema.json | 46 +- artiq/coredevice/fmcdio_vhdci_eem.py | 51 - artiq/coredevice/novogorny.py | 174 - artiq/coredevice/sawg.py | 372 -- artiq/coredevice/shiftreg.py | 54 - artiq/coredevice/spline.py | 228 -- artiq/firmware/libboard_artiq/ad9154.rs | 549 --- artiq/firmware/libboard_artiq/ad9154_reg.rs | 826 ----- artiq/firmware/libboard_artiq/hmc830_7043.rs | 419 --- artiq/firmware/libboard_artiq/lib.rs | 7 - artiq/firmware/libboard_artiq/si5324.rs | 6 - artiq/firmware/libboard_artiq/wrpll.rs | 2 - artiq/firmware/libboard_misoc/net_settings.rs | 8 - artiq/firmware/libboard_misoc/spiflash.rs | 2 +- artiq/firmware/runtime/main.rs | 2 +- artiq/firmware/runtime/rtio_clocking.rs | 6 +- artiq/firmware/satman/jdac_common.rs | 74 - artiq/firmware/satman/jdcg.rs | 589 ---- artiq/firmware/satman/main.rs | 54 - artiq/frontend/artiq_ddb_template.py | 28 - artiq/frontend/artiq_flash.py | 138 +- artiq/gateware/dsp/__init__.py | 0 artiq/gateware/dsp/accu.py | 112 - artiq/gateware/dsp/fir.py | 172 - artiq/gateware/dsp/sawg.py | 220 -- artiq/gateware/dsp/spline.py | 47 - artiq/gateware/dsp/tools.py | 69 - artiq/gateware/eem.py | 47 - artiq/gateware/eem_7series.py | 8 - artiq/gateware/fmcdio_vhdci_eem.py | 29 - artiq/gateware/jesd204_tools.py | 290 -- artiq/gateware/rtio/phy/sawg.py | 39 - artiq/gateware/targets/metlino.py | 180 - artiq/gateware/targets/sayma_amc.py | 462 --- artiq/gateware/targets/sayma_rtm.py | 280 -- artiq/gateware/test/dsp/__init__.py | 0 artiq/gateware/test/dsp/fir.py | 112 - artiq/gateware/test/dsp/test_accu.py | 46 - artiq/gateware/test/dsp/test_satadd.py | 71 - artiq/gateware/test/dsp/test_sawg.py | 36 - artiq/gateware/test/dsp/test_sawg_fe.py | 255 -- artiq/gateware/test/dsp/test_sawg_phy.py | 70 - artiq/gateware/test/dsp/test_spline.py | 31 - artiq/gateware/test/dsp/tools.py | 49 - artiq/test/test_coefficients.py | 49 - artiq/test/test_wavesynth.py | 127 - artiq/wavesynth/__init__.py | 0 artiq/wavesynth/coefficients.py | 234 -- artiq/wavesynth/compute_samples.py | 133 - doc/manual/core_drivers_reference.rst | 31 - doc/manual/utilities.rst | 3 - flake.nix | 14 +- 55 files changed, 13 insertions(+), 9936 deletions(-) delete mode 100644 artiq/coredevice/ad9154_reg.py delete mode 100644 artiq/coredevice/ad9154_spi.py delete mode 100644 artiq/coredevice/basemod_att.py delete mode 100644 artiq/coredevice/fmcdio_vhdci_eem.py delete mode 100644 artiq/coredevice/novogorny.py delete mode 100644 artiq/coredevice/sawg.py delete mode 100644 artiq/coredevice/shiftreg.py delete mode 100644 artiq/coredevice/spline.py delete mode 100644 artiq/firmware/libboard_artiq/ad9154.rs delete mode 100644 artiq/firmware/libboard_artiq/ad9154_reg.rs delete mode 100644 artiq/firmware/libboard_artiq/hmc830_7043.rs delete mode 100644 artiq/firmware/satman/jdac_common.rs delete mode 100644 artiq/firmware/satman/jdcg.rs delete mode 100644 artiq/gateware/dsp/__init__.py delete mode 100644 artiq/gateware/dsp/accu.py delete mode 100644 artiq/gateware/dsp/fir.py delete mode 100644 artiq/gateware/dsp/sawg.py delete mode 100644 artiq/gateware/dsp/spline.py delete mode 100644 artiq/gateware/dsp/tools.py delete mode 100644 artiq/gateware/fmcdio_vhdci_eem.py delete mode 100644 artiq/gateware/jesd204_tools.py delete mode 100644 artiq/gateware/rtio/phy/sawg.py delete mode 100755 artiq/gateware/targets/metlino.py delete mode 100755 artiq/gateware/targets/sayma_amc.py delete mode 100755 artiq/gateware/targets/sayma_rtm.py delete mode 100644 artiq/gateware/test/dsp/__init__.py delete mode 100644 artiq/gateware/test/dsp/fir.py delete mode 100644 artiq/gateware/test/dsp/test_accu.py delete mode 100644 artiq/gateware/test/dsp/test_satadd.py delete mode 100644 artiq/gateware/test/dsp/test_sawg.py delete mode 100644 artiq/gateware/test/dsp/test_sawg_fe.py delete mode 100644 artiq/gateware/test/dsp/test_sawg_phy.py delete mode 100644 artiq/gateware/test/dsp/test_spline.py delete mode 100644 artiq/gateware/test/dsp/tools.py delete mode 100644 artiq/test/test_coefficients.py delete mode 100644 artiq/test/test_wavesynth.py delete mode 100644 artiq/wavesynth/__init__.py delete mode 100644 artiq/wavesynth/coefficients.py delete mode 100644 artiq/wavesynth/compute_samples.py diff --git a/artiq/coredevice/ad9154_reg.py b/artiq/coredevice/ad9154_reg.py deleted file mode 100644 index a7d414e96..000000000 --- a/artiq/coredevice/ad9154_reg.py +++ /dev/null @@ -1,2996 +0,0 @@ -# auto-generated, do not edit -from artiq.language.core import portable -from artiq.language.types import TInt32 - -AD9154_SPI_INTFCONFA = 0x000 -# default: 0x00, access: R/W -@portable -def AD9154_SOFTRESET_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_SOFTRESET_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LSBFIRST_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_LSBFIRST_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ADDRINC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_ADDRINC_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SDOACTIVE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SDOACTIVE_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SDOACTIVE_M_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SDOACTIVE_M_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ADDRINC_M_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_ADDRINC_M_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LSBFIRST_M_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_LSBFIRST_M_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SOFTRESET_M_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_SOFTRESET_M_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_CHIPTYPE = 0x003 - -AD9154_PRODIDL = 0x004 - -AD9154_PRODIDH = 0x005 - -AD9154_CHIPGRADE = 0x006 -# default: 0x02, access: R -@portable -def AD9154_DEV_REVISION_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R -@portable -def AD9154_PROD_GRADE_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_SPI_PAGEINDX = 0x008 - -AD9154_PWRCNTRL0 = 0x011 -# default: 0x01, access: R/W -@portable -def AD9154_PD_DAC3_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_PD_DAC3_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_DAC2_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_PD_DAC2_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_DAC1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_PD_DAC1_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_DAC0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_PD_DAC0_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PD_BG_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_PD_BG_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_TXENMASK1 = 0x012 -# default: 0x00, access: R/W -@portable -def AD9154_DACA_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_DACA_MASK_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_DACB_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_DACB_MASK_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_PWRCNTRL3 = 0x013 -# default: 0x00, access: R/W -@portable -def AD9154_SPI_TXEN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_SPI_TXEN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ENA_SPI_TXEN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_ENA_SPI_TXEN_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_PA_CTRL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_PA_CTRL_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ENA_PA_CTRL_FROM_SPI_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_ENA_PA_CTRL_FROM_SPI_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ENA_PA_CTRL_FROM_BLSM_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_ENA_PA_CTRL_FROM_BLSM_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_ENA_PA_CTRL_FROM_TXENSM_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_ENA_PA_CTRL_FROM_TXENSM_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ENA_PA_CTRL_FROM_PARROT_ERR_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_ENA_PA_CTRL_FROM_PARROT_ERR_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_GROUP_DLY = 0x014 -# default: 0x08, access: R/W -@portable -def AD9154_COARSE_GROUP_DELAY_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_COARSE_GROUP_DELAY_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x08, access: R/W -@portable -def AD9154_GROUP_DELAY_RESERVED_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_GROUP_DELAY_RESERVED_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_IRQEN_STATUSMODE0 = 0x01f -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_LANEFIFOERR_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_IRQEN_SMODE_LANEFIFOERR_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SERPLLLOCK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_IRQEN_SMODE_SERPLLLOCK_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SERPLLLOST_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_IRQEN_SMODE_SERPLLLOST_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_DACPLLLOCK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_IRQEN_SMODE_DACPLLLOCK_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_DACPLLLOST_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_IRQEN_SMODE_DACPLLLOST_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_IRQEN_STATUSMODE1 = 0x020 -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PRBS0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_IRQEN_SMODE_PRBS0_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PRBS1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_IRQEN_SMODE_PRBS1_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PRBS2_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_IRQEN_SMODE_PRBS2_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PRBS3_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_IRQEN_SMODE_PRBS3_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - - -AD9154_IRQEN_STATUSMODE2 = 0x021 -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_TRIP0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_IRQEN_SMODE_SYNC_TRIP0_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_WLIM0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_IRQEN_SMODE_SYNC_WLIM0_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_ROTATE0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_IRQEN_SMODE_SYNC_ROTATE0_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_LOCK0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_IRQEN_SMODE_SYNC_LOCK0_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_NCO_ALIGN0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_IRQEN_SMODE_NCO_ALIGN0_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_BLNKDONE0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_IRQEN_SMODE_BLNKDONE0_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PDPERR0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_IRQEN_SMODE_PDPERR0_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_IRQEN_STATUSMODE3 = 0x022 -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_TRIP1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_IRQEN_SMODE_SYNC_TRIP1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_WLIM1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_IRQEN_SMODE_SYNC_WLIM1_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_ROTATE1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_IRQEN_SMODE_SYNC_ROTATE1_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_LOCK1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_IRQEN_SMODE_SYNC_LOCK1_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_NCO_ALIGN1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_IRQEN_SMODE_NCO_ALIGN1_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_BLNKDONE1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_IRQEN_SMODE_BLNKDONE1_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PDPERR1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_IRQEN_SMODE_PDPERR1_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_IRQ_STATUS0 = 0x023 -# default: 0x00, access: R -@portable -def AD9154_LANEFIFOERR_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERPLLLOCK_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERPLLLOST_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_DACPLLLOCK_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_DACPLLLOST_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_IRQ_STATUS1 = 0x024 -# default: 0x00, access: R -@portable -def AD9154_PRBS0_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PRBS1_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PRBS2_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PRBS3_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - - -AD9154_IRQ_STATUS2 = 0x025 -# default: 0x00, access: R -@portable -def AD9154_SYNC_TRIP0_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_WLIM0_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_ROTATE0_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_LOCK0_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_NCO_ALIGN0_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_BLNKDONE0_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PDPERR0_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_IRQ_STATUS3 = 0x026 -# default: 0x00, access: R -@portable -def AD9154_SYNC_TRIP1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_WLIM1_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_ROTATE1_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_LOCK1_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_NCO_ALIGN1_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_BLNKDONE1_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PDPERR1_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_JESD_CHECKS = 0x030 -# default: 0x00, access: R -@portable -def AD9154_ERR_INTSUPP_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ERR_SUBCLASS_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ERR_KUNSUPP_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ERR_JESDBAD_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ERR_WINLIMIT_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ERR_DLYOVER_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_SYNC_ERRWINDOW = 0x034 - -AD9154_SYNC_LASTERR_L = 0x038 - -AD9154_SYNC_LASTERR_H = 0x039 -# default: 0x00, access: R -@portable -def AD9154_LASTERROR_H_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_LASTOVER_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_LASTUNDER_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_SYNC_CONTROL = 0x03a -# default: 0x00, access: R/W -@portable -def AD9154_SYNCMODE_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_SYNCMODE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R/W -@portable -def AD9154_SYNCCLRLAST_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SYNCCLRLAST_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SYNCCLRSTKY_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_SYNCCLRSTKY_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SYNCARM_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_SYNCARM_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SYNCENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_SYNCENABLE_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_SYNC_STATUS = 0x03b -# default: 0x00, access: R -@portable -def AD9154_SYNC_TRIP_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_WLIM_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_ROTATE_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_LOCK_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_BUSY_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_SYNC_CURRERR_L = 0x03c - -AD9154_SYNC_CURRERR_H = 0x03d -# default: 0x00, access: R -@portable -def AD9154_CURRERROR_H_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_CURROVER_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_CURRUNDER_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACGAIN0_I = 0x040 - -AD9154_DACGAIN1_I = 0x041 - -AD9154_DACGAIN0_Q = 0x042 - -AD9154_DACGAIN1_Q = 0x043 - -AD9154_GROUPDELAY_COMP_I = 0x044 - -AD9154_GROUPDELAY_COMP_Q = 0x045 - -AD9154_GROUPDELAY_COMP_BYP = 0x046 -# default: 0x01, access: R/W -@portable -def AD9154_GROUPCOMP_BYPQ_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_GROUPCOMP_BYPQ_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_GROUPCOMP_BYPI_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_GROUPCOMP_BYPI_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - - -AD9154_MIX_MODE = 0x04a - -AD9154_NCOALIGN_MODE = 0x050 -# default: 0x00, access: R/W -@portable -def AD9154_NCO_ALIGN_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_NCO_ALIGN_MODE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R -@portable -def AD9154_NCO_ALIGN_FAIL_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_NCO_ALIGN_PASS_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_NCO_ALIGN_MTCH_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_NCO_ALIGN_ARM_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_NCO_ALIGN_ARM_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_NCOKEY_ILSB = 0x051 - -AD9154_NCOKEY_IMSB = 0x052 - -AD9154_NCOKEY_QLSB = 0x053 - -AD9154_NCOKEY_QMSB = 0x054 - -AD9154_PDP_THRES0 = 0x060 - -AD9154_PDP_THRES1 = 0x061 - -AD9154_PDP_AVG_TIME = 0x062 -# default: 0x00, access: R/W -@portable -def AD9154_PDP_AVG_TIME__SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_PDP_AVG_TIME__GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R/W -@portable -def AD9154_PA_BUS_SWAP_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_PA_BUS_SWAP_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PDP_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_PDP_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_PDP_POWER0 = 0x063 - -AD9154_PDP_POWER1 = 0x064 - -AD9154_CLKCFG0 = 0x080 -# default: 0x00, access: R/W -@portable -def AD9154_REF_CLKDIV_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_REF_CLKDIV_EN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_RF_SYNC_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_RF_SYNC_EN_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_DUTY_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_DUTY_EN_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_CLK_REC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_PD_CLK_REC_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_SERDES_PCLK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_PD_SERDES_PCLK_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_CLK_DIG_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_PD_CLK_DIG_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_CLK23_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_PD_CLK23_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_CLK01_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_PD_CLK01_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_SYSREF_ACTRL0 = 0x081 -# default: 0x00, access: R/W -@portable -def AD9154_HYS_CNTRL1_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_HYS_CNTRL1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_SYSREF_RISE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SYSREF_RISE_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_HYS_ON_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_HYS_ON_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_SYSREF_BUFFER_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_PD_SYSREF_BUFFER_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - - -AD9154_SYSREF_ACTRL1 = 0x082 - -AD9154_DACPLLCNTRL = 0x083 -# default: 0x00, access: R/W -@portable -def AD9154_ENABLE_DACPLL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_ENABLE_DACPLL_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_RECAL_DACPLL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_RECAL_DACPLL_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACPLLSTATUS = 0x084 -# default: 0x00, access: R -@portable -def AD9154_DACPLL_LOCK_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_VCO_CAL_PROGRESS_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_CP_CAL_VALID_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_CP_OVERRANGE_L_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_CP_OVERRANGE_H_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_DACINTEGERWORD0 = 0x085 - -AD9154_DACLOOPFILT1 = 0x087 -# default: 0x08, access: R/W -@portable -def AD9154_LF_C1_WORD_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_LF_C1_WORD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x08, access: R/W -@portable -def AD9154_LF_C2_WORD_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_LF_C2_WORD_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_DACLOOPFILT2 = 0x088 -# default: 0x08, access: R/W -@portable -def AD9154_LF_C3_WORD_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_LF_C3_WORD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x08, access: R/W -@portable -def AD9154_LF_R1_WORD_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_LF_R1_WORD_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_DACLOOPFILT3 = 0x089 -# default: 0x08, access: R/W -@portable -def AD9154_LF_R3_WORD_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_LF_R3_WORD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R/W -@portable -def AD9154_LF_BYPASS_C1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_LF_BYPASS_C1_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LF_BYPASS_C2_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_LF_BYPASS_C2_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LF_BYPASS_R1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_LF_BYPASS_R1_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LF_BYPASS_R3_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_LF_BYPASS_R3_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACCPCNTRL = 0x08a -# default: 0x20, access: R/W -@portable -def AD9154_CP_CURRENT_SET(x: TInt32) -> TInt32: - return (x & 0x3f) << 0 - -@portable -def AD9154_CP_CURRENT_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3f - -# default: 0x00, access: R/W -@portable -def AD9154_VT_FORCE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_VT_FORCE_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_DACLOGENCNTRL = 0x08b -# default: 0x00, access: R/W -@portable -def AD9154_LODIVMODE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_LODIVMODE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_LO_POWER_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 4 - -@portable -def AD9154_LO_POWER_MODE_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x3 - - -AD9154_DACLDOCNTRL1 = 0x08c -# default: 0x00, access: R/W -@portable -def AD9154_REFDIVMODE_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_REFDIVMODE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x00, access: R/W -@portable -def AD9154_LDO_BYPASS_FLT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_LDO_BYPASS_FLT_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LDO_REF_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_LDO_REF_SEL_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACLDOCNTRL2 = 0x08d -# default: 0x03, access: R/W -@portable -def AD9154_LDO_VDROP_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_LDO_VDROP_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x02, access: R/W -@portable -def AD9154_LDO_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 2 - -@portable -def AD9154_LDO_SEL_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_LDO_INRUSH_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 5 - -@portable -def AD9154_LDO_INRUSH_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_LDO_BYPASS_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_LDO_BYPASS_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DATA_FORMAT = 0x110 -# default: 0x00, access: R/W -@portable -def AD9154_BINARY_FORMAT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_BINARY_FORMAT_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DATAPATH_CTRL = 0x111 -# default: 0x00, access: R/W -@portable -def AD9154_I_TO_Q_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_I_TO_Q_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SEL_SIDEBAND_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_SEL_SIDEBAND_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_MODULATION_TYPE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 2 - -@portable -def AD9154_MODULATION_TYPE_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_PHASE_ADJ_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_PHASE_ADJ_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_DIG_GAIN_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_DIG_GAIN_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_INVSINC_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_INVSINC_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_INTERP_MODE = 0x112 - -AD9154_NCO_FTW_UPDATE = 0x113 -# default: 0x00, access: R/W -@portable -def AD9154_FTW_UPDATE_REQ_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_FTW_UPDATE_REQ_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_FTW_UPDATE_ACK_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - - -AD9154_FTW0 = 0x114 - -AD9154_FTW1 = 0x115 - -AD9154_FTW2 = 0x116 - -AD9154_FTW3 = 0x117 - -AD9154_FTW4 = 0x118 - -AD9154_FTW5 = 0x119 - -AD9154_NCO_PHASE_OFFSET0 = 0x11a - -AD9154_NCO_PHASE_OFFSET1 = 0x11b - -AD9154_PHASE_ADJ0 = 0x11c - -AD9154_PHASE_ADJ1 = 0x11d - -AD9154_TXEN_SM_0 = 0x11f -# default: 0x01, access: R/W -@portable -def AD9154_TXEN_SM_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_TXEN_SM_EN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_GP_PA_CTRL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_GP_PA_CTRL_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_GP_PA_ON_INVERT_SET(x: TInt32) -> TInt32: - return (x & 0x0) << 2 - -@portable -def AD9154_GP_PA_ON_INVERT_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x0 - -# default: 0x00, access: R/W -@portable -def AD9154_RISE_COUNTERS_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 4 - -@portable -def AD9154_RISE_COUNTERS_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x3 - -# default: 0x02, access: R/W -@portable -def AD9154_FALL_COUNTERS_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 6 - -@portable -def AD9154_FALL_COUNTERS_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_TXEN_RISE_COUNT_0 = 0x121 - -AD9154_TXEN_RISE_COUNT_1 = 0x122 - -AD9154_TXEN_FALL_COUNT_0 = 0x123 - -AD9154_TXEN_FALL_COUNT_1 = 0x124 - -AD9154_DEVICE_CONFIG_REG_0 = 0x12d - -AD9154_DIE_TEMP_CTRL0 = 0x12f -# default: 0x00, access: R/W -@portable -def AD9154_AUXADC_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_AUXADC_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x10, access: R/W -@portable -def AD9154_AUXADC_RESERVED_SET(x: TInt32) -> TInt32: - return (x & 0x7f) << 1 - -@portable -def AD9154_AUXADC_RESERVED_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x7f - - -AD9154_DIE_TEMP0 = 0x132 - -AD9154_DIE_TEMP1 = 0x133 - -AD9154_DIE_TEMP_UPDATE = 0x134 - -AD9154_DC_OFFSET_CTRL = 0x135 - -AD9154_IPATH_DC_OFFSET_1PART0 = 0x136 - -AD9154_IPATH_DC_OFFSET_1PART1 = 0x137 - -AD9154_QPATH_DC_OFFSET_1PART0 = 0x138 - -AD9154_QPATH_DC_OFFSET_1PART1 = 0x139 - -AD9154_IPATH_DC_OFFSET_2PART = 0x13a - -AD9154_QPATH_DC_OFFSET_2PART = 0x13b - -AD9154_IDAC_DIG_GAIN0 = 0x13c - -AD9154_IDAC_DIG_GAIN1 = 0x13d - -AD9154_QDAC_DIG_GAIN0 = 0x13e - -AD9154_QDAC_DIG_GAIN1 = 0x13f - -AD9154_GAIN_RAMP_UP_STEP0 = 0x140 - -AD9154_GAIN_RAMP_UP_STEP1 = 0x141 - -AD9154_GAIN_RAMP_DOWN_STEP0 = 0x142 - -AD9154_GAIN_RAMP_DOWN_STEP1 = 0x143 - -AD9154_DEVICE_CONFIG_REG_1 = 0x146 - -AD9154_BSM_STAT = 0x147 -# default: 0x00, access: R -@portable -def AD9154_SOFTBLANKRB_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_PRBS = 0x14b -# default: 0x00, access: R/W -@portable -def AD9154_PRBS_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_PRBS_EN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PRBS_RESET_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_PRBS_RESET_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PRBS_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_PRBS_MODE_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PRBS_GOOD_I_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PRBS_GOOD_Q_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_PRBS_ERROR_I = 0x14c - -AD9154_PRBS_ERROR_Q = 0x14d - -AD9154_DACPLLT0 = 0x1b0 -# default: 0x01, access: R/W -@portable -def AD9154_LOGEN_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_LOGEN_PD_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_LDO_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_LDO_PD_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SYNTH_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SYNTH_PD_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_VCO_PD_ALC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_VCO_PD_ALC_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_VCO_PD_PTAT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_VCO_PD_PTAT_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_VCO_PD_IN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_VCO_PD_IN_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACPLLT1 = 0x1b1 -# default: 0x00, access: R/W -@portable -def AD9154_PFD_EDGE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_PFD_EDGE_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PFD_DELAY_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 2 - -@portable -def AD9154_PFD_DELAY_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x3 - - -AD9154_DACPLLT2 = 0x1b2 -# default: 0x00, access: R/W -@portable -def AD9154_EXT_ALC_WORD_SET(x: TInt32) -> TInt32: - return (x & 0x7f) << 0 - -@portable -def AD9154_EXT_ALC_WORD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7f - -# default: 0x00, access: R/W -@portable -def AD9154_EXT_ALC_WORD_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_EXT_ALC_WORD_EN_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACPLLT3 = 0x1b3 -# default: 0x00, access: W -@portable -def AD9154_EXT_BAND1_SET(x: TInt32) -> TInt32: - return (x & 0xff) << 0 - - -AD9154_DACPLLT4 = 0x1b4 -# default: 0x00, access: R/W -@portable -def AD9154_EXT_BAND2_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_EXT_BAND2_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_EXT_BAND_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_EXT_BAND_EN_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x0f, access: R/W -@portable -def AD9154_VCO_CAL_OFFSET_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 3 - -@portable -def AD9154_VCO_CAL_OFFSET_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0xf - -# default: 0x00, access: R/W -@portable -def AD9154_BYP_LOAD_DELAY_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_BYP_LOAD_DELAY_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACPLLT5 = 0x1b5 - -AD9154_DACPLLT6 = 0x1b6 - -AD9154_DACPLLT7 = 0x1b7 - -AD9154_DACPLLT8 = 0x1b8 - -AD9154_DACPLLT9 = 0x1b9 - -AD9154_DACPLLTA = 0x1ba - -AD9154_DACPLLTB = 0x1bb -# default: 0x04, access: R/W -@portable -def AD9154_VCO_BIAS_REF_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_VCO_BIAS_REF_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_VCO_BIAS_TCF_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 3 - -@portable -def AD9154_VCO_BIAS_TCF_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x3 - - -AD9154_DACPLLTC = 0x1bc - -AD9154_DACPLLTD = 0x1bd - -AD9154_DACPLLTE = 0x1be - -AD9154_DACPLLTF = 0x1bf - -AD9154_DACPLLT10 = 0x1c0 - -AD9154_DACPLLT11 = 0x1c1 - -AD9154_DACPLLT15 = 0x1c2 - -AD9154_DACPLLT16 = 0x1c3 - -AD9154_DACPLLT17 = 0x1c4 - -AD9154_DACPLLT18 = 0x1c5 - -AD9154_MASTER_PD = 0x200 - -AD9154_PHY_PD = 0x201 - -AD9154_GENERIC_PD = 0x203 -# default: 0x00, access: R/W -@portable -def AD9154_PD_SYNCOUT1B_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_PD_SYNCOUT1B_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PD_SYNCOUT0B_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_PD_SYNCOUT0B_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - - -AD9154_CDR_RESET = 0x206 - -AD9154_CDR_OPERATING_MODE_REG_0 = 0x230 -# default: 0x00, access: R/W -@portable -def AD9154_CDR_OVERSAMP_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_CDR_OVERSAMP_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x02, access: R/W -@portable -def AD9154_CDR_RESERVED_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 2 - -@portable -def AD9154_CDR_RESERVED_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_ENHALFRATE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_ENHALFRATE_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_EQ_BIAS_REG = 0x268 -# default: 0x22, access: R/W -@portable -def AD9154_EQ_BIAS_RESERVED_SET(x: TInt32) -> TInt32: - return (x & 0x3f) << 0 - -@portable -def AD9154_EQ_BIAS_RESERVED_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3f - -# default: 0x01, access: R/W -@portable -def AD9154_EQ_POWER_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 6 - -@portable -def AD9154_EQ_POWER_MODE_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_SERDESPLL_ENABLE_CNTRL = 0x280 -# default: 0x00, access: R/W -@portable -def AD9154_ENABLE_SERDESPLL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_ENABLE_SERDESPLL_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_RECAL_SERDESPLL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_RECAL_SERDESPLL_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - - -AD9154_PLL_STATUS = 0x281 -# default: 0x00, access: R -@portable -def AD9154_SERDES_PLL_LOCK_RB_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERDES_CURRENTS_READY_RB_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERDES_VCO_CAL_IN_PROGRESS_RB_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERDES_PLL_CAL_VALID_RB_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERDES_PLL_OVERRANGE_L_RB_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERDES_PLL_OVERRANGE_H_RB_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_LDO_FILTER_1 = 0x284 - -AD9154_LDO_FILTER_2 = 0x285 - -AD9154_LDO_FILTER_3 = 0x286 - -AD9154_CP_CURRENT_SPI = 0x287 -# default: 0x3f, access: R/W -@portable -def AD9154_SPI_CP_CURRENT_SET(x: TInt32) -> TInt32: - return (x & 0x3f) << 0 - -@portable -def AD9154_SPI_CP_CURRENT_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3f - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_SERDES_LOGEN_POWER_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_SPI_SERDES_LOGEN_POWER_MODE_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_REF_CLK_DIVIDER_LDO = 0x289 -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CDR_OVERSAMP_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_SPI_CDR_OVERSAMP_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_LDO_BYPASS_FILT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_LDO_BYPASS_FILT_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_LDO_REF_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SPI_LDO_REF_SEL_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - - -AD9154_VCO_LDO = 0x28a - -AD9154_PLL_RD_REG = 0x28b -# default: 0x01, access: R/W -@portable -def AD9154_SPI_SERDES_LOGEN_PD_CORE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_SPI_SERDES_LOGEN_PD_CORE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_SERDES_LDO_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_SERDES_LDO_PD_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_SYN_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SPI_SYN_PD_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_VCO_PD_ALC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SPI_VCO_PD_ALC_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_VCO_PD_PTAT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_SPI_VCO_PD_PTAT_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_VCO_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_SPI_VCO_PD_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_ALC_VARACTOR = 0x290 -# default: 0x03, access: R/W -@portable -def AD9154_SPI_VCO_VARACTOR_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_SPI_VCO_VARACTOR_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x08, access: R/W -@portable -def AD9154_SPI_INIT_ALC_VALUE_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_SPI_INIT_ALC_VALUE_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_VCO_OUTPUT = 0x291 -# default: 0x09, access: R/W -@portable -def AD9154_SPI_VCO_OUTPUT_LEVEL_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_SPI_VCO_OUTPUT_LEVEL_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x04, access: R/W -@portable -def AD9154_SPI_VCO_OUTPUT_RESERVED_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_SPI_VCO_OUTPUT_RESERVED_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_CP_CONFIG = 0x294 -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CP_TEST_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_SPI_CP_TEST_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CP_CAL_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_CP_CAL_EN_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CP_FORCE_CALBITS_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SPI_CP_FORCE_CALBITS_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_CP_OFFSET_OFF_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SPI_CP_OFFSET_OFF_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_CP_ENABLE_MACHINE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_SPI_CP_ENABLE_MACHINE_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CP_DITHER_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_SPI_CP_DITHER_MODE_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_CP_HALF_VCO_CAL_CLK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_SPI_CP_HALF_VCO_CAL_CLK_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_VCO_BIAS_1 = 0x296 -# default: 0x04, access: R/W -@portable -def AD9154_SPI_VCO_BIAS_REF_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_SPI_VCO_BIAS_REF_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_VCO_BIAS_TCF_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 3 - -@portable -def AD9154_SPI_VCO_BIAS_TCF_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x3 - - -AD9154_VCO_BIAS_2 = 0x297 -# default: 0x00, access: R/W -@portable -def AD9154_SPI_PRESCALE_BIAS_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_SPI_PRESCALE_BIAS_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_LAST_ALC_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_LAST_ALC_EN_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_PRESCALE_BYPASS_R_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SPI_PRESCALE_BYPASS_R_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_COMP_BYPASS_BIASR_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SPI_VCO_COMP_BYPASS_BIASR_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_BYPASS_DAC_R_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_SPI_VCO_BYPASS_DAC_R_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_VCO_PD_OVERRIDES = 0x299 -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VCO_BUF_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VCO_BUF_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_CAL_TCF_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_CAL_TCF_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_TCF_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_TCF_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - - -AD9154_VCO_CAL = 0x29a -# default: 0x02, access: R/W -@portable -def AD9154_SPI_FB_CLOCK_ADV_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_SPI_FB_CLOCK_ADV_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x03, access: R/W -@portable -def AD9154_SPI_VCO_CAL_COUNT_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 2 - -@portable -def AD9154_SPI_VCO_CAL_COUNT_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x3 - -# default: 0x07, access: R/W -@portable -def AD9154_SPI_VCO_CAL_ALC_WAIT_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 4 - -@portable -def AD9154_SPI_VCO_CAL_ALC_WAIT_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_VCO_CAL_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_SPI_VCO_CAL_EN_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_CP_LEVEL_DETECT = 0x29c -# default: 0x07, access: R/W -@portable -def AD9154_SPI_CP_LEVEL_THRESHOLD_HIGH_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_SPI_CP_LEVEL_THRESHOLD_HIGH_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x02, access: R/W -@portable -def AD9154_SPI_CP_LEVEL_THRESHOLD_LOW_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 3 - -@portable -def AD9154_SPI_CP_LEVEL_THRESHOLD_LOW_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x7 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CP_LEVEL_DET_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_SPI_CP_LEVEL_DET_PD_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_VCO_VARACTOR_CTRL_0 = 0x29f -# default: 0x03, access: R/W -@portable -def AD9154_SPI_VCO_VARACTOR_OFFSET_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_SPI_VCO_VARACTOR_OFFSET_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x03, access: R/W -@portable -def AD9154_SPI_VCO_VARACTOR_REF_TCF_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 4 - -@portable -def AD9154_SPI_VCO_VARACTOR_REF_TCF_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x7 - - -AD9154_VCO_VARACTOR_CTRL_1 = 0x2a0 -# default: 0x08, access: R/W -@portable -def AD9154_SPI_VCO_VARACTOR_REF_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_SPI_VCO_VARACTOR_REF_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - - -AD9154_TERM_BLK1_CTRLREG0 = 0x2a7 - -AD9154_TERM_BLK2_CTRLREG0 = 0x2ae - -AD9154_GENERAL_JRX_CTRL_0 = 0x300 -# default: 0x00, access: R/W -@portable -def AD9154_LINK_EN_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_LINK_EN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_LINK_PAGE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_LINK_PAGE_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LINK_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_LINK_MODE_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_CHECKSUM_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_CHECKSUM_MODE_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_GENERAL_JRX_CTRL_1 = 0x301 - -AD9154_DYN_LINK_LATENCY_0 = 0x302 - -AD9154_DYN_LINK_LATENCY_1 = 0x303 - -AD9154_LMFC_DELAY_0 = 0x304 - -AD9154_LMFC_DELAY_1 = 0x305 - -AD9154_LMFC_VAR_0 = 0x306 - -AD9154_LMFC_VAR_1 = 0x307 - -AD9154_XBAR_LN_0_1 = 0x308 -# default: 0x00, access: R/W -@portable -def AD9154_LOGICAL_LANE0_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_LOGICAL_LANE0_SRC_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_LOGICAL_LANE1_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 3 - -@portable -def AD9154_LOGICAL_LANE1_SRC_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x7 - - -AD9154_XBAR_LN_2_3 = 0x309 -# default: 0x02, access: R/W -@portable -def AD9154_LOGICAL_LANE2_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_LOGICAL_LANE2_SRC_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x03, access: R/W -@portable -def AD9154_LOGICAL_LANE3_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 3 - -@portable -def AD9154_LOGICAL_LANE3_SRC_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x7 - - -AD9154_XBAR_LN_4_5 = 0x30a -# default: 0x04, access: R/W -@portable -def AD9154_LOGICAL_LANE4_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_LOGICAL_LANE4_SRC_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x05, access: R/W -@portable -def AD9154_LOGICAL_LANE5_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 3 - -@portable -def AD9154_LOGICAL_LANE5_SRC_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x7 - - -AD9154_XBAR_LN_6_7 = 0x30b -# default: 0x06, access: R/W -@portable -def AD9154_LOGICAL_LANE6_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_LOGICAL_LANE6_SRC_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x07, access: R/W -@portable -def AD9154_LOGICAL_LANE7_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 3 - -@portable -def AD9154_LOGICAL_LANE7_SRC_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x7 - - -AD9154_FIFO_STATUS_REG_0 = 0x30c - -AD9154_FIFO_STATUS_REG_1 = 0x30d - -AD9154_SYNCB_GEN_1 = 0x312 -# default: 0x00, access: R/W -@portable -def AD9154_SYNCB_ERR_DUR_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 4 - -@portable -def AD9154_SYNCB_ERR_DUR_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x7 - - -AD9154_SERDES_SPI_REG = 0x314 - -AD9154_PHY_PRBS_TEST_EN = 0x315 - -AD9154_PHY_PRBS_TEST_CTRL = 0x316 -# default: 0x00, access: R/W -@portable -def AD9154_PHY_TEST_RESET_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_PHY_TEST_RESET_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PHY_TEST_START_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_PHY_TEST_START_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PHY_PRBS_PAT_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 2 - -@portable -def AD9154_PHY_PRBS_PAT_SEL_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_PHY_SRC_ERR_CNT_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 4 - -@portable -def AD9154_PHY_SRC_ERR_CNT_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x7 - - -AD9154_PHY_PRBS_TEST_THRESHOLD_LOBITS = 0x317 - -AD9154_PHY_PRBS_TEST_THRESHOLD_MIDBITS = 0x318 - -AD9154_PHY_PRBS_TEST_THRESHOLD_HIBITS = 0x319 - -AD9154_PHY_PRBS_TEST_ERRCNT_LOBITS = 0x31a - -AD9154_PHY_PRBS_TEST_ERRCNT_MIDBITS = 0x31b - -AD9154_PHY_PRBS_TEST_ERRCNT_HIBITS = 0x31c - -AD9154_PHY_PRBS_TEST_STATUS = 0x31d - -AD9154_SHORT_TPL_TEST_0 = 0x32c -# default: 0x00, access: R/W -@portable -def AD9154_SHORT_TPL_TEST_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_SHORT_TPL_TEST_EN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SHORT_TPL_TEST_RESET_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_SHORT_TPL_TEST_RESET_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SHORT_TPL_DAC_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 2 - -@portable -def AD9154_SHORT_TPL_DAC_SEL_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_SHORT_TPL_SP_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 4 - -@portable -def AD9154_SHORT_TPL_SP_SEL_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x3 - - -AD9154_SHORT_TPL_TEST_1 = 0x32d - -AD9154_SHORT_TPL_TEST_2 = 0x32e - -AD9154_SHORT_TPL_TEST_3 = 0x32f - -AD9154_DEVICE_CONFIG_REG_2 = 0x333 - -AD9154_JESD_BIT_INVERSE_CTRL = 0x334 - -AD9154_DID_REG = 0x400 - -AD9154_BID_REG = 0x401 -# default: 0x00, access: R -@portable -def AD9154_BID_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R -@portable -def AD9154_ADJCNT_RD_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_LID0_REG = 0x402 -# default: 0x00, access: R -@portable -def AD9154_LID0_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_PHADJ_RD_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ADJDIR_RD_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_SCR_L_REG = 0x403 -# default: 0x00, access: R -@portable -def AD9154_L_1_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_SCR_RD_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_F_REG = 0x404 - -AD9154_K_REG = 0x405 - -AD9154_M_REG = 0x406 - -AD9154_CS_N_REG = 0x407 -# default: 0x00, access: R -@portable -def AD9154_N_1_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_CS_RD_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_NP_REG = 0x408 -# default: 0x00, access: R -@portable -def AD9154_NP_1_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_SUBCLASSV_RD_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x7 - - -AD9154_S_REG = 0x409 -# default: 0x00, access: R -@portable -def AD9154_S_1_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_JESDV_RD_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x7 - - -AD9154_HD_CF_REG = 0x40a -# default: 0x00, access: R -@portable -def AD9154_CF_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_HD_RD_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_RES1_REG = 0x40b - -AD9154_RES2_REG = 0x40c - -AD9154_CHECKSUM0_REG = 0x40d - -AD9154_COMPSUM0_REG = 0x40e - -AD9154_LID1_REG = 0x412 - -AD9154_CHECKSUM1_REG = 0x415 - -AD9154_COMPSUM1_REG = 0x416 - -AD9154_LID2_REG = 0x41a - -AD9154_CHECKSUM2_REG = 0x41d - -AD9154_COMPSUM2_REG = 0x41e - -AD9154_LID3_REG = 0x422 - -AD9154_CHECKSUM3_REG = 0x425 - -AD9154_COMPSUM3_REG = 0x426 - -AD9154_LID4_REG = 0x42a - -AD9154_CHECKSUM4_REG = 0x42d - -AD9154_COMPSUM4_REG = 0x42e - -AD9154_LID5_REG = 0x432 - -AD9154_CHECKSUM5_REG = 0x435 - -AD9154_COMPSUM5_REG = 0x436 - -AD9154_LID6_REG = 0x43a - -AD9154_CHECKSUM6_REG = 0x43d - -AD9154_COMPSUM6_REG = 0x43e - -AD9154_LID7_REG = 0x442 - -AD9154_CHECKSUM7_REG = 0x445 - -AD9154_COMPSUM7_REG = 0x446 - -AD9154_ILS_DID = 0x450 - -AD9154_ILS_BID = 0x451 -# default: 0x00, access: R/W -@portable -def AD9154_BID_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_BID_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R/W -@portable -def AD9154_ADJCNT_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_ADJCNT_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_ILS_LID0 = 0x452 -# default: 0x00, access: R/W -@portable -def AD9154_LID0_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_LID0_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R/W -@portable -def AD9154_PHADJ_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_PHADJ_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ADJDIR_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_ADJDIR_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_ILS_SCR_L = 0x453 -# default: 0x03, access: R/W -@portable -def AD9154_L_1_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_L_1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x01, access: R/W -@portable -def AD9154_SCR_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_SCR_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_ILS_F = 0x454 - -AD9154_ILS_K = 0x455 - -AD9154_ILS_M = 0x456 - -AD9154_ILS_CS_N = 0x457 -# default: 0x0f, access: R/W -@portable -def AD9154_N_1_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_N_1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R/W -@portable -def AD9154_CS_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 6 - -@portable -def AD9154_CS_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_ILS_NP = 0x458 -# default: 0x0f, access: R/W -@portable -def AD9154_NP_1_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_NP_1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x01, access: R/W -@portable -def AD9154_SUBCLASSV_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 5 - -@portable -def AD9154_SUBCLASSV_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x7 - - -AD9154_ILS_S = 0x459 -# default: 0x00, access: R/W -@portable -def AD9154_S_1_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_S_1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x01, access: R/W -@portable -def AD9154_JESDV_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 5 - -@portable -def AD9154_JESDV_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x7 - - -AD9154_ILS_HD_CF = 0x45a -# default: 0x00, access: R/W -@portable -def AD9154_CF_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_CF_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x01, access: R/W -@portable -def AD9154_HD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_HD_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_ILS_RES1 = 0x45b - -AD9154_ILS_RES2 = 0x45c - -AD9154_ILS_CHECKSUM = 0x45d - -AD9154_ERRCNTRMON = 0x46b -# default: 0x00, access: W -@portable -def AD9154_CNTRSEL_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -# default: 0x00, access: W -@portable -def AD9154_LANESEL_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 4 - - -AD9154_LANEDESKEW = 0x46c - -AD9154_BADDISPARITY = 0x46d -# default: 0x00, access: W -@portable -def AD9154_LANE_ADDR_DIS_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -# default: 0x00, access: W -@portable -def AD9154_RST_ERR_CNTR_DIS_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -# default: 0x00, access: W -@portable -def AD9154_DISABLE_ERR_CNTR_DIS_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -# default: 0x00, access: W -@portable -def AD9154_RST_IRQ_DIS_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - - -AD9154_NIT_W = 0x46e -# default: 0x00, access: W -@portable -def AD9154_LANE_ADDR_NIT_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -# default: 0x00, access: W -@portable -def AD9154_RST_ERR_CNTR_NIT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -# default: 0x00, access: W -@portable -def AD9154_DISABLE_ERR_CNTR_NIT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -# default: 0x00, access: W -@portable -def AD9154_RST_IRQ_NIT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - - -AD9154_UNEXPECTEDCONTROL_W = 0x46f -# default: 0x00, access: W -@portable -def AD9154_LANE_ADDR_UCC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -# default: 0x00, access: W -@portable -def AD9154_RST_ERR_CNTR_UCC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -# default: 0x00, access: W -@portable -def AD9154_DISABLE_ERR_CNTR_UCC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -# default: 0x00, access: W -@portable -def AD9154_RST_IRQ_UCC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - - -AD9154_CODEGRPSYNCFLG = 0x470 - -AD9154_FRAMESYNCFLG = 0x471 - -AD9154_GOODCHKSUMFLG = 0x472 - -AD9154_INITLANESYNCFLG = 0x473 - -AD9154_CTRLREG1 = 0x476 - -AD9154_CTRLREG2 = 0x477 -# default: 0x00, access: R/W -@portable -def AD9154_THRESHOLD_MASK_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_THRESHOLD_MASK_EN_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ILAS_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_ILAS_MODE_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_KVAL = 0x478 - -AD9154_IRQVECTOR_MASK = 0x47a -# default: 0x00, access: W -@portable -def AD9154_CODEGRPSYNC_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -# default: 0x00, access: W -@portable -def AD9154_BADCHECKSUM_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -# default: 0x00, access: W -@portable -def AD9154_INITIALLANESYNC_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -# default: 0x00, access: W -@portable -def AD9154_UCC_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -# default: 0x00, access: W -@portable -def AD9154_NIT_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -# default: 0x00, access: W -@portable -def AD9154_BADDIS_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - - -AD9154_SYNCASSERTIONMASK = 0x47b -# default: 0x01, access: R/W -@portable -def AD9154_CMM_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_CMM_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_CMM_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_CMM_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_UCC_S_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_UCC_S_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_NIT_S_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_NIT_S_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_BADDIS_S_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_BADDIS_S_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_ERRORTHRES = 0x47c - -AD9154_LANEENABLE = 0x47d - -AD9154_RAMP_ENA = 0x47e - -AD9154_DIG_TEST0 = 0x520 -# default: 0x00, access: R/W -@portable -def AD9154_DC_TEST_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_DC_TEST_MODE_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - - -AD9154_DC_TEST_VALUEI0 = 0x521 - -AD9154_DC_TEST_VALUEI1 = 0x522 - -AD9154_DC_TEST_VALUEQ0 = 0x523 - -AD9154_DC_TEST_VALUEQ1 = 0x524 diff --git a/artiq/coredevice/ad9154_spi.py b/artiq/coredevice/ad9154_spi.py deleted file mode 100644 index d83a85ff6..000000000 --- a/artiq/coredevice/ad9154_spi.py +++ /dev/null @@ -1,23 +0,0 @@ -from artiq.language.core import kernel - - -class AD9154: - """Kernel interface to AD9154 registers, using non-realtime SPI.""" - - def __init__(self, dmgr, spi_device, chip_select): - self.core = dmgr.get("core") - self.bus = dmgr.get(spi_device) - self.chip_select = chip_select - - @kernel - def setup_bus(self, div=16): - self.bus.set_config_mu(0, 24, div, self.chip_select) - - @kernel - def write(self, addr, data): - self.bus.write((addr << 16) | (data<< 8)) - - @kernel - def read(self, addr): - self.write((1 << 15) | addr, 0) - return self.bus.read() diff --git a/artiq/coredevice/basemod_att.py b/artiq/coredevice/basemod_att.py deleted file mode 100644 index 5015324ff..000000000 --- a/artiq/coredevice/basemod_att.py +++ /dev/null @@ -1,79 +0,0 @@ -from artiq.language.core import kernel, portable, delay -from artiq.language.units import us, ms -from artiq.coredevice.shiftreg import ShiftReg - - -@portable -def to_mu(att): - return round(att*2.0) ^ 0x3f - -@portable -def from_mu(att_mu): - return 0.5*(att_mu ^ 0x3f) - - -class BaseModAtt: - def __init__(self, dmgr, rst_n, clk, le, mosi, miso): - self.rst_n = dmgr.get(rst_n) - self.shift_reg = ShiftReg(dmgr, - clk=clk, ser=mosi, latch=le, ser_in=miso, n=8*4) - - @kernel - def reset(self): - # HMC's incompetence in digital design and interfaces means that - # the HMC542 needs a level low on RST_N and then a rising edge - # on Latch Enable. Their "latch" isn't a latch but a DFF. - # Of course, it also powers up with a random attenuation, and - # that cannot be fixed with simple pull-ups/pull-downs. - self.rst_n.off() - self.shift_reg.latch.off() - delay(1*us) - self.shift_reg.latch.on() - delay(1*us) - self.shift_reg.latch.off() - self.rst_n.on() - delay(1*us) - - @kernel - def set_mu(self, att0, att1, att2, att3): - """ - Sets the four attenuators on BaseMod. - The values are in half decibels, between 0 (no attenuation) - and 63 (31.5dB attenuation). - """ - word = ( - (att0 << 2) | - (att1 << 10) | - (att2 << 18) | - (att3 << 26) - ) - self.shift_reg.set(word) - - @kernel - def get_mu(self): - """ - Retrieves the current settings of the four attenuators on BaseMod. - """ - word = self.shift_reg.get() - att0 = (word >> 2) & 0x3f - att1 = (word >> 10) & 0x3f - att2 = (word >> 18) & 0x3f - att3 = (word >> 26) & 0x3f - return att0, att1, att2, att3 - - @kernel - def set(self, att0, att1, att2, att3): - """ - Sets the four attenuators on BaseMod. - The values are in decibels. - """ - self.set_mu(to_mu(att0), to_mu(att1), to_mu(att2), to_mu(att3)) - - @kernel - def get(self): - """ - Retrieves the current settings of the four attenuators on BaseMod. - The values are in decibels. - """ - att0, att1, att2, att3 = self.get_mu() - return from_mu(att0), from_mu(att1), from_mu(att2), from_mu(att3) diff --git a/artiq/coredevice/coredevice_generic.schema.json b/artiq/coredevice/coredevice_generic.schema.json index f5d096788..2f90924b9 100644 --- a/artiq/coredevice/coredevice_generic.schema.json +++ b/artiq/coredevice/coredevice_generic.schema.json @@ -134,7 +134,7 @@ "properties": { "type": { "type": "string", - "enum": ["dio", "urukul", "novogorny", "sampler", "suservo", "zotino", "grabber", "mirny", "fastino", "phaser", "hvamp"] + "enum": ["dio", "urukul", "sampler", "suservo", "zotino", "grabber", "mirny", "fastino", "phaser", "hvamp"] }, "board": { "type": "string" @@ -230,50 +230,6 @@ }, "required": ["ports"] } - }, { - "title": "Novogorny", - "if": { - "properties": { - "type": { - "const": "novogorny" - } - } - }, - "then": { - "properties": { - "ports": { - "type": "array", - "items": { - "type": "integer" - }, - "minItems": 1, - "maxItems": 1 - } - }, - "required": ["ports"] - } - }, { - "title": "Sampler", - "if": { - "properties": { - "type": { - "const": "sampler" - } - } - }, - "then": { - "properties": { - "ports": { - "type": "array", - "items": { - "type": "integer" - }, - "minItems": 1, - "maxItems": 2 - } - }, - "required": ["ports"] - } }, { "title": "SUServo", "if": { diff --git a/artiq/coredevice/fmcdio_vhdci_eem.py b/artiq/coredevice/fmcdio_vhdci_eem.py deleted file mode 100644 index bddb55812..000000000 --- a/artiq/coredevice/fmcdio_vhdci_eem.py +++ /dev/null @@ -1,51 +0,0 @@ -# Definitions for using the "FMC DIO 32ch LVDS a" card with the VHDCI-EEM breakout v1.1 - -eem_fmc_connections = { - 0: [0, 8, 2, 3, 4, 5, 6, 7], - 1: [1, 9, 10, 11, 12, 13, 14, 15], - 2: [17, 16, 24, 19, 20, 21, 22, 23], - 3: [18, 25, 26, 27, 28, 29, 30, 31], -} - - -def shiftreg_bits(eem, out_pins): - """ - Returns the bits that have to be set in the FMC card direction - shift register for the given EEM. - - Takes a set of pin numbers (0-7) at the EEM. Return values - of this function for different EEMs should be ORed together. - """ - r = 0 - for i in range(8): - if i not in out_pins: - lvds_line = eem_fmc_connections[eem][i] - # lines are swapped in pairs to ease PCB routing - # at the shift register - shift = lvds_line ^ 1 - r |= 1 << shift - return r - - -dio_bank0_out_pins = set(range(4)) -dio_bank1_out_pins = set(range(4, 8)) -urukul_out_pins = { - 0, # clk - 1, # mosi - 3, 4, 5, # cs_n - 6, # io_update - 7, # dds_reset -} -urukul_aux_out_pins = { - 4, # sw0 - 5, # sw1 - 6, # sw2 - 7, # sw3 -} -zotino_out_pins = { - 0, # clk - 1, # mosi - 3, 4, # cs_n - 5, # ldac_n - 7, # clr_n -} diff --git a/artiq/coredevice/novogorny.py b/artiq/coredevice/novogorny.py deleted file mode 100644 index 49bb9a22c..000000000 --- a/artiq/coredevice/novogorny.py +++ /dev/null @@ -1,174 +0,0 @@ -from artiq.language.core import kernel, delay, portable -from artiq.language.units import ns - -from artiq.coredevice import spi2 as spi - - -SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | - 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) - - -SPI_CS_ADC = 1 -SPI_CS_SR = 2 - - -@portable -def adc_ctrl(channel=1, softspan=0b111, valid=1): - """Build a LTC2335-16 control word""" - return (valid << 7) | (channel << 3) | softspan - - -@portable -def adc_softspan(data): - """Return the softspan configuration index from a result packet""" - return data & 0x7 - - -@portable -def adc_channel(data): - """Return the channel index from a result packet""" - return (data >> 3) & 0x7 - - -@portable -def adc_data(data): - """Return the ADC value from a result packet""" - return (data >> 8) & 0xffff - - -@portable -def adc_value(data, v_ref=5.): - """Convert a ADC result packet to SI units (Volt)""" - softspan = adc_softspan(data) - data = adc_data(data) - g = 625 - if softspan & 4: - g *= 2 - if softspan & 2: - h = 1 << 15 - else: - h = 1 << 16 - data = -(data & h) + (data & ~h) - if softspan & 1: - h *= 500 - else: - h *= 512 - v_per_lsb = v_ref*g/h - return data*v_per_lsb - - -class Novogorny: - """Novogorny ADC. - - Controls the LTC2335-16 8 channel ADC with SPI interface and - the switchable gain instrumentation amplifiers using a shift - register. - - :param spi_device: SPI bus device name - :param cnv_device: CNV RTIO TTLOut channel name - :param div: SPI clock divider (default: 8) - :param gains: Initial value for PGIA gains shift register - (default: 0x0000). Knowledge of this state is not transferred - between experiments. - :param core_device: Core device name - """ - kernel_invariants = {"bus", "core", "cnv", "div", "v_ref"} - - def __init__(self, dmgr, spi_device, cnv_device, div=8, gains=0x0000, - core_device="core"): - self.bus = dmgr.get(spi_device) - self.core = dmgr.get(core_device) - self.cnv = dmgr.get(cnv_device) - self.div = div - self.gains = gains - self.v_ref = 5. # 5 Volt reference - - @kernel - def set_gain_mu(self, channel, gain): - """Set instrumentation amplifier gain of a channel. - - The four gain settings (0, 1, 2, 3) corresponds to gains of - (1, 10, 100, 1000) respectively. - - :param channel: Channel index - :param gain: Gain setting - """ - gains = self.gains - gains &= ~(0b11 << (channel*2)) - gains |= gain << (channel*2) - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, - 16, self.div, SPI_CS_SR) - self.bus.write(gains << 16) - self.gains = gains - - @kernel - def configure(self, data): - """Set up the ADC sequencer. - - :param data: List of 8 bit control words to write into the sequencer - table. - """ - if len(data) > 1: - self.bus.set_config_mu(SPI_CONFIG, - 8, self.div, SPI_CS_ADC) - for i in range(len(data) - 1): - self.bus.write(data[i] << 24) - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, - 8, self.div, SPI_CS_ADC) - self.bus.write(data[len(data) - 1] << 24) - - @kernel - def sample_mu(self, next_ctrl=0): - """Acquire a sample: - - Perform a conversion and transfer the sample. - - :param next_ctrl: ADC control word for the next sample - :return: The ADC result packet (machine units) - """ - self.cnv.pulse(40*ns) # t_CNVH - delay(560*ns) # t_CONV max - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, - 24, self.div, SPI_CS_ADC) - self.bus.write(next_ctrl << 24) - return self.bus.read() - - @kernel - def sample(self, next_ctrl=0): - """Acquire a sample - - .. seealso:: :meth:`sample_mu` - - :param next_ctrl: ADC control word for the next sample - :return: The ADC result packet (Volt) - """ - return adc_value(self.sample_mu(), self.v_ref) - - @kernel - def burst_mu(self, data, dt_mu, ctrl=0): - """Acquire a burst of samples. - - If the burst is too long and the sample rate too high, there will be - RTIO input overflows. - - High sample rates lead to gain errors since the impedance between the - instrumentation amplifier and the ADC is high. - - :param data: List of data values to write result packets into. - In machine units. - :param dt: Sample interval in machine units. - :param ctrl: ADC control word to write during each result packet - transfer. - """ - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, - 24, self.div, SPI_CS_ADC) - for i in range(len(data)): - t0 = now_mu() - self.cnv.pulse(40*ns) # t_CNVH - delay(560*ns) # t_CONV max - self.bus.write(ctrl << 24) - at_mu(t0 + dt_mu) - for i in range(len(data)): - data[i] = self.bus.read() diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py deleted file mode 100644 index 0a5905fa7..000000000 --- a/artiq/coredevice/sawg.py +++ /dev/null @@ -1,372 +0,0 @@ -""" -Driver for the Smart Arbitrary Waveform Generator (SAWG) on RTIO. - -The SAWG is an "improved DDS" built in gateware and interfacing to -high-speed DACs. - -Output event replacement is supported except on the configuration channel. -""" - - -from artiq.language.types import TInt32, TFloat -from numpy import int32, int64 -from artiq.language.core import kernel -from artiq.coredevice.spline import Spline -from artiq.coredevice.rtio import rtio_output - - -# sawg.Config addresses -_SAWG_DIV = 0 -_SAWG_CLR = 1 -_SAWG_IQ_EN = 2 -# _SAWF_PAD = 3 # reserved -_SAWG_OUT_MIN = 4 -_SAWG_OUT_MAX = 5 -_SAWG_DUC_MIN = 6 -_SAWG_DUC_MAX = 7 - - -class Config: - """SAWG configuration. - - Exposes the configurable quantities of a single SAWG channel. - - Access to the configuration registers for a SAWG channel can not - be concurrent. There must be at least :attr:`_rtio_interval` machine - units of delay between accesses. Replacement is not supported and will be - lead to an ``RTIOCollision`` as this is likely a programming error. - All methods therefore advance the timeline by the duration of one - configuration register transfer. - - :param channel: RTIO channel number of the channel. - :param core: Core device. - """ - kernel_invariants = {"channel", "core", "_out_scale", "_duc_scale", - "_rtio_interval"} - - def __init__(self, channel, core, cordic_gain=1.): - self.channel = channel - self.core = core - # normalized DAC output - self._out_scale = (1 << 15) - 1. - # normalized DAC output including DUC cordic gain - self._duc_scale = self._out_scale/cordic_gain - # configuration channel access interval - self._rtio_interval = int64(3*self.core.ref_multiplier) - - @kernel - def set_div(self, div: TInt32, n: TInt32=0): - """Set the spline evolution divider and current counter value. - - The divider and the spline evolution are synchronized across all - spline channels within a SAWG channel. The DDS/DUC phase accumulators - always evolves at full speed. - - .. note:: The spline evolution divider has not been tested extensively - and is currently considered a technological preview only. - - :param div: Spline evolution divider, such that - ``t_sawg_spline/t_rtio_coarse = div + 1``. Default: ``0``. - :param n: Current value of the counter. Default: ``0``. - """ - rtio_output((self.channel << 8) | _SAWG_DIV, div | (n << 16)) - delay_mu(self._rtio_interval) - - @kernel - def set_clr(self, clr0: TInt32, clr1: TInt32, clr2: TInt32): - """Set the accumulator clear mode for the three phase accumulators. - - When the ``clr`` bit for a given DDS/DUC phase accumulator is - set, that phase accumulator will be cleared with every phase offset - RTIO command and the output phase of the DDS/DUC will be - exactly the phase RTIO value ("absolute phase update mode"). - - .. math:: - q^\prime(t) = p^\prime + (t - t^\prime) f^\prime - - In turn, when the bit is cleared, the phase RTIO channels - determine a phase offset to the current (carrier-) value of the - DDS/DUC phase accumulator. This "relative phase update mode" is - sometimes also called “continuous phase mode”. - - .. math:: - q^\prime(t) = q(t^\prime) + (p^\prime - p) + - (t - t^\prime) f^\prime - - Where: - - * :math:`q`, :math:`q^\prime`: old/new phase accumulator - * :math:`p`, :math:`p^\prime`: old/new phase offset - * :math:`f^\prime`: new frequency - * :math:`t^\prime`: timestamp of setting new :math:`p`, :math:`f` - * :math:`t`: running time - - :param clr0: Auto-clear phase accumulator of the ``phase0``/ - ``frequency0`` DUC. Default: ``True`` - :param clr1: Auto-clear phase accumulator of the ``phase1``/ - ``frequency1`` DDS. Default: ``True`` - :param clr2: Auto-clear phase accumulator of the ``phase2``/ - ``frequency2`` DDS. Default: ``True`` - """ - rtio_output((self.channel << 8) | _SAWG_CLR, clr0 | - (clr1 << 1) | (clr2 << 2)) - delay_mu(self._rtio_interval) - - @kernel - def set_iq_en(self, i_enable: TInt32, q_enable: TInt32): - """Enable I/Q data on this DAC channel. - - Every pair of SAWG channels forms a buddy pair. - The ``iq_en`` configuration controls which DDS data is emitted to the - DACs. - - Refer to the documentation of :class:`SAWG` for a mathematical - description of ``i_enable`` and ``q_enable``. - - .. note:: Quadrature data from the buddy channel is currently - a technological preview only. The data is ignored in the SAWG - gateware and not added to the DAC output. - This is equivalent to the ``q_enable`` switch always being ``0``. - - :param i_enable: Controls adding the in-phase - DUC-DDS data of *this* SAWG channel to *this* DAC channel. - Default: ``1``. - :param q_enable: controls adding the quadrature - DUC-DDS data of this SAWG's *buddy* channel to *this* DAC - channel. Default: ``0``. - """ - rtio_output((self.channel << 8) | _SAWG_IQ_EN, i_enable | - (q_enable << 1)) - delay_mu(self._rtio_interval) - - @kernel - def set_duc_max_mu(self, limit: TInt32): - """Set the digital up-converter (DUC) I and Q data summing junctions - upper limit. In machine units. - - The default limits are chosen to reach maximum and minimum DAC output - amplitude. - - For a description of the limiter functions in normalized units see: - - .. seealso:: :meth:`set_duc_max` - """ - rtio_output((self.channel << 8) | _SAWG_DUC_MAX, limit) - delay_mu(self._rtio_interval) - - @kernel - def set_duc_min_mu(self, limit: TInt32): - """.. seealso:: :meth:`set_duc_max_mu`""" - rtio_output((self.channel << 8) | _SAWG_DUC_MIN, limit) - delay_mu(self._rtio_interval) - - @kernel - def set_out_max_mu(self, limit: TInt32): - """.. seealso:: :meth:`set_duc_max_mu`""" - rtio_output((self.channel << 8) | _SAWG_OUT_MAX, limit) - delay_mu(self._rtio_interval) - - @kernel - def set_out_min_mu(self, limit: TInt32): - """.. seealso:: :meth:`set_duc_max_mu`""" - rtio_output((self.channel << 8) | _SAWG_OUT_MIN, limit) - delay_mu(self._rtio_interval) - - @kernel - def set_duc_max(self, limit: TFloat): - """Set the digital up-converter (DUC) I and Q data summing junctions - upper limit. - - Each of the three summing junctions has a saturating adder with - configurable upper and lower limits. The three summing junctions are: - - * At the in-phase input to the ``phase0``/``frequency0`` fast DUC, - after the anti-aliasing FIR filter. - * At the quadrature input to the ``phase0``/``frequency0`` - fast DUC, after the anti-aliasing FIR filter. The in-phase and - quadrature data paths both use the same limits. - * Before the DAC, where the following three data streams - are added together: - - * the output of the ``offset`` spline, - * (optionally, depending on ``i_enable``) the in-phase output - of the ``phase0``/``frequency0`` fast DUC, and - * (optionally, depending on ``q_enable``) the quadrature - output of the ``phase0``/``frequency0`` fast DUC of the - buddy channel. - - Refer to the documentation of :class:`SAWG` for a mathematical - description of the summing junctions. - - :param limit: Limit value ``[-1, 1]``. The output of the limiter will - never exceed this limit. The default limits are the full range - ``[-1, 1]``. - - .. seealso:: - * :meth:`set_duc_max`: Upper limit of the in-phase and quadrature - inputs to the DUC. - * :meth:`set_duc_min`: Lower limit of the in-phase and quadrature - inputs to the DUC. - * :meth:`set_out_max`: Upper limit of the DAC output. - * :meth:`set_out_min`: Lower limit of the DAC output. - """ - self.set_duc_max_mu(int32(round(limit*self._duc_scale))) - - @kernel - def set_duc_min(self, limit: TFloat): - """.. seealso:: :meth:`set_duc_max`""" - self.set_duc_min_mu(int32(round(limit*self._duc_scale))) - - @kernel - def set_out_max(self, limit: TFloat): - """.. seealso:: :meth:`set_duc_max`""" - self.set_out_max_mu(int32(round(limit*self._out_scale))) - - @kernel - def set_out_min(self, limit: TFloat): - """.. seealso:: :meth:`set_duc_max`""" - self.set_out_min_mu(int32(round(limit*self._out_scale))) - - -class SAWG: - """Smart arbitrary waveform generator channel. - The channel is parametrized as: :: - - oscillators = exp(2j*pi*(frequency0*t + phase0))*( - amplitude1*exp(2j*pi*(frequency1*t + phase1)) + - amplitude2*exp(2j*pi*(frequency2*t + phase2))) - - output = (offset + - i_enable*Re(oscillators) + - q_enable*Im(buddy_oscillators)) - - This parametrization can be viewed as two complex (quadrature) oscillators - (``frequency1``/``phase1`` and ``frequency2``/``phase2``) that are - executing and sampling at the coarse RTIO frequency. They can represent - frequencies within the first Nyquist zone from ``-f_rtio_coarse/2`` to - ``f_rtio_coarse/2``. - - .. note:: The coarse RTIO frequency ``f_rtio_coarse`` is the inverse of - ``ref_period*multiplier``. Both are arguments of the ``Core`` device, - specified in the device database ``device_db.py``. - - The sum of their outputs is then interpolated by a factor of - :attr:`parallelism` (2, 4, 8 depending on the bitstream) using a - finite-impulse-response (FIR) anti-aliasing filter (more accurately - a half-band filter). - - The filter is followed by a configurable saturating limiter. - - After the limiter, the data is shifted in frequency using a complex - digital up-converter (DUC, ``frequency0``/``phase0``) running at - :attr:`parallelism` times the coarse RTIO frequency. The first Nyquist - zone of the DUC extends from ``-f_rtio_coarse*parallelism/2`` to - ``f_rtio_coarse*parallelism/2``. Other Nyquist zones are usable depending - on the interpolation/modulation options configured in the DAC. - - The real/in-phase data after digital up-conversion can be offset using - another spline interpolator ``offset``. - - The ``i_enable``/``q_enable`` switches enable emission of quadrature - signals for later analog quadrature mixing distinguishing upper and lower - sidebands and thus doubling the bandwidth. They can also be used to emit - four-tone signals. - - .. note:: Quadrature data from the buddy channel is currently - ignored in the SAWG gateware and not added to the DAC output. - This is equivalent to the ``q_enable`` switch always being ``0``. - - The configuration channel and the nine - :class:`artiq.coredevice.spline.Spline` interpolators are accessible as - attributes: - - * :attr:`config`: :class:`Config` - * :attr:`offset`, :attr:`amplitude1`, :attr:`amplitude2`: in units - of full scale - * :attr:`phase0`, :attr:`phase1`, :attr:`phase2`: in units of turns - * :attr:`frequency0`, :attr:`frequency1`, :attr:`frequency2`: in units - of Hz - - .. note:: The latencies (pipeline depths) of the nine data channels (i.e. - all except :attr:`config`) are matched. Equivalent channels (e.g. - :attr:`phase1` and :attr:`phase2`) are exactly matched. Channels of - different type or functionality (e.g. :attr:`offset` vs - :attr:`amplitude1`, DDS vs DUC, :attr:`phase0` vs :attr:`phase1`) are - only matched to within one coarse RTIO cycle. - - :param channel_base: RTIO channel number of the first channel (amplitude). - The configuration channel and frequency/phase/amplitude channels are - then assumed to be successive channels. - :param parallelism: Number of output samples per coarse RTIO clock cycle. - :param core_device: Name of the core device that this SAWG is on. - """ - kernel_invariants = {"channel_base", "core", "parallelism", - "amplitude1", "frequency1", "phase1", - "amplitude2", "frequency2", "phase2", - "frequency0", "phase0", "offset"} - - def __init__(self, dmgr, channel_base, parallelism, core_device="core"): - self.core = dmgr.get(core_device) - self.channel_base = channel_base - self.parallelism = parallelism - width = 16 - time_width = 16 - cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain - head_room = 1.001 - self.config = Config(channel_base, self.core, cordic_gain) - self.offset = Spline(width, time_width, channel_base + 1, - self.core, 2.*head_room) - self.amplitude1 = Spline(width, time_width, channel_base + 2, - self.core, 2*head_room*cordic_gain**2) - self.frequency1 = Spline(3*width, time_width, channel_base + 3, - self.core, 1/self.core.coarse_ref_period) - self.phase1 = Spline(width, time_width, channel_base + 4, - self.core, 1.) - self.amplitude2 = Spline(width, time_width, channel_base + 5, - self.core, 2*head_room*cordic_gain**2) - self.frequency2 = Spline(3*width, time_width, channel_base + 6, - self.core, 1/self.core.coarse_ref_period) - self.phase2 = Spline(width, time_width, channel_base + 7, - self.core, 1.) - self.frequency0 = Spline(2*width, time_width, channel_base + 8, - self.core, - parallelism/self.core.coarse_ref_period) - self.phase0 = Spline(width, time_width, channel_base + 9, - self.core, 1.) - - @kernel - def reset(self): - """Re-establish initial conditions. - - This clears all spline interpolators, accumulators and configuration - settings. - - This method advances the timeline by the time required to perform all - 7 writes to the configuration channel, plus 9 coarse RTIO cycles. - """ - self.config.set_div(0, 0) - self.config.set_clr(1, 1, 1) - self.config.set_iq_en(1, 0) - self.config.set_duc_min(-1.) - self.config.set_duc_max(1.) - self.config.set_out_min(-1.) - self.config.set_out_max(1.) - self.frequency0.set_mu(0) - coarse_cycle = int64(self.core.ref_multiplier) - delay_mu(coarse_cycle) - self.frequency1.set_mu(0) - delay_mu(coarse_cycle) - self.frequency2.set_mu(0) - delay_mu(coarse_cycle) - self.phase0.set_mu(0) - delay_mu(coarse_cycle) - self.phase1.set_mu(0) - delay_mu(coarse_cycle) - self.phase2.set_mu(0) - delay_mu(coarse_cycle) - self.amplitude1.set_mu(0) - delay_mu(coarse_cycle) - self.amplitude2.set_mu(0) - delay_mu(coarse_cycle) - self.offset.set_mu(0) - delay_mu(coarse_cycle) diff --git a/artiq/coredevice/shiftreg.py b/artiq/coredevice/shiftreg.py deleted file mode 100644 index 79000eba3..000000000 --- a/artiq/coredevice/shiftreg.py +++ /dev/null @@ -1,54 +0,0 @@ -from artiq.language.core import kernel, delay -from artiq.language.units import us - - -class ShiftReg: - """Driver for shift registers/latch combos connected to TTLs""" - kernel_invariants = {"dt", "n"} - - def __init__(self, dmgr, clk, ser, latch, n=32, dt=10*us, ser_in=None): - self.core = dmgr.get("core") - self.clk = dmgr.get(clk) - self.ser = dmgr.get(ser) - self.latch = dmgr.get(latch) - self.n = n - self.dt = dt - if ser_in is not None: - self.ser_in = dmgr.get(ser_in) - - @kernel - def set(self, data): - """Sets the values of the latch outputs. This does not - advance the timeline and the waveform is generated before - `now`.""" - delay(-2*(self.n + 1)*self.dt) - for i in range(self.n): - if (data >> (self.n-i-1)) & 1 == 0: - self.ser.off() - else: - self.ser.on() - self.clk.off() - delay(self.dt) - self.clk.on() - delay(self.dt) - self.clk.off() - self.latch.on() - delay(self.dt) - self.latch.off() - delay(self.dt) - - @kernel - def get(self): - delay(-2*(self.n + 1)*self.dt) - data = 0 - for i in range(self.n): - data <<= 1 - self.ser_in.sample_input() - if self.ser_in.sample_get(): - data |= 1 - delay(self.dt) - self.clk.on() - delay(self.dt) - self.clk.off() - delay(self.dt) - return data diff --git a/artiq/coredevice/spline.py b/artiq/coredevice/spline.py deleted file mode 100644 index 9f8310d1e..000000000 --- a/artiq/coredevice/spline.py +++ /dev/null @@ -1,228 +0,0 @@ -from numpy import int32, int64 -from artiq.language.core import kernel, portable, delay -from artiq.coredevice.rtio import rtio_output, rtio_output_wide -from artiq.language.types import TInt32, TInt64, TFloat - - -class Spline: - r"""Spline interpolating RTIO channel. - - One knot of a polynomial basis spline (B-spline) :math:`u(t)` - is defined by the coefficients :math:`u_n` up to order :math:`n = k`. - If the coefficients are evaluated starting at time :math:`t_0`, - the output :math:`u(t)` for :math:`t > t_0, t_0` is: - - .. math:: - u(t) &= \sum_{n=0}^k \frac{u_n}{n!} (t - t_0)^n \\ - &= u_0 + u_1 (t - t_0) + \frac{u_2}{2} (t - t_0)^2 + \dots - - This class contains multiple methods to convert spline knot data from SI - to machine units and multiple methods that set the current spline - coefficient data. None of these advance the timeline. The :meth:`smooth` - method is the only method that advances the timeline. - - :param width: Width in bits of the quantity that this spline controls - :param time_width: Width in bits of the time counter of this spline - :param channel: RTIO channel number - :param core_device: Core device that this spline is attached to - :param scale: Scale for conversion between machine units and physical - units; to be given as the "full scale physical value". - """ - - kernel_invariants = {"channel", "core", "scale", "width", - "time_width", "time_scale"} - - def __init__(self, width, time_width, channel, core_device, scale=1.): - self.core = core_device - self.channel = channel - self.width = width - self.scale = float((int64(1) << width) / scale) - self.time_width = time_width - self.time_scale = float((1 << time_width) * - core_device.coarse_ref_period) - - @portable(flags={"fast-math"}) - def to_mu(self, value: TFloat) -> TInt32: - """Convert floating point ``value`` from physical units to 32 bit - integer machine units.""" - return int32(round(value*self.scale)) - - @portable(flags={"fast-math"}) - def from_mu(self, value: TInt32) -> TFloat: - """Convert 32 bit integer ``value`` from machine units to floating - point physical units.""" - return value/self.scale - - @portable(flags={"fast-math"}) - def to_mu64(self, value: TFloat) -> TInt64: - """Convert floating point ``value`` from physical units to 64 bit - integer machine units.""" - return int64(round(value*self.scale)) - - @kernel - def set_mu(self, value: TInt32): - """Set spline value (machine units). - - :param value: Spline value in integer machine units. - """ - rtio_output(self.channel << 8, value) - - @kernel(flags={"fast-math"}) - def set(self, value: TFloat): - """Set spline value. - - :param value: Spline value relative to full-scale. - """ - if self.width > 32: - l = [int32(0)] * 2 - self.pack_coeff_mu([self.to_mu64(value)], l) - rtio_output_wide(self.channel << 8, l) - else: - rtio_output(self.channel << 8, self.to_mu(value)) - - @kernel - def set_coeff_mu(self, value): # TList(TInt32) - """Set spline raw values. - - :param value: Spline packed raw values. - """ - rtio_output_wide(self.channel << 8, value) - - @portable(flags={"fast-math"}) - def pack_coeff_mu(self, coeff, packed): # TList(TInt64), TList(TInt32) - """Pack coefficients into RTIO data - - :param coeff: TList(TInt64) list of machine units spline coefficients. - Lowest (zeroth) order first. The coefficient list is zero-extended - by the RTIO gateware. - :param packed: TList(TInt32) list for packed RTIO data. Must be - pre-allocated. Length in bits is - ``n*width + (n - 1)*n//2*time_width`` - """ - pos = 0 - for i in range(len(coeff)): - wi = self.width + i*self.time_width - ci = coeff[i] - while wi != 0: - j = pos//32 - used = pos - 32*j - avail = 32 - used - if avail > wi: - avail = wi - cij = int32(ci) - if avail != 32: - cij &= (1 << avail) - 1 - packed[j] |= cij << used - ci >>= avail - wi -= avail - pos += avail - - @portable(flags={"fast-math"}) - def coeff_to_mu(self, coeff, coeff64): # TList(TFloat), TList(TInt64) - """Convert a floating point list of coefficients into a 64 bit - integer (preallocated). - - :param coeff: TList(TFloat) list of coefficients in physical units. - :param coeff64: TList(TInt64) preallocated list of coefficients in - machine units. - """ - for i in range(len(coeff)): - vi = coeff[i] * self.scale - for j in range(i): - vi *= self.time_scale - ci = int64(round(vi)) - coeff64[i] = ci - # artiq.wavesynth.coefficients.discrete_compensate: - if i == 2: - coeff64[1] += ci >> self.time_width + 1 - elif i == 3: - coeff64[2] += ci >> self.time_width - coeff64[1] += ci // 6 >> 2*self.time_width - - def coeff_as_packed_mu(self, coeff64): - """Pack 64 bit integer machine units coefficients into 32 bit integer - RTIO data list. - - This is a host-only method that can be used to generate packed - spline coefficient data to be frozen into kernels at compile time. - """ - n = len(coeff64) - width = n*self.width + (n - 1)*n//2*self.time_width - packed = [int32(0)] * ((width + 31)//32) - self.pack_coeff_mu(coeff64, packed) - return packed - - def coeff_as_packed(self, coeff): - """Convert floating point spline coefficients into 32 bit integer - packed data. - - This is a host-only method that can be used to generate packed - spline coefficient data to be frozen into kernels at compile time. - """ - coeff64 = [int64(0)] * len(coeff) - self.coeff_to_mu(coeff, coeff64) - return self.coeff_as_packed_mu(coeff64) - - @kernel(flags={"fast-math"}) - def set_coeff(self, coeff): # TList(TFloat) - """Set spline coefficients. - - Missing coefficients (high order) are zero-extended byt the RTIO - gateware. - - If more coefficients are supplied than the gateware supports the extra - coefficients are ignored. - - :param value: List of floating point spline coefficients, - lowest order (constant) coefficient first. Units are the - unit of this spline's value times increasing powers of 1/s. - """ - n = len(coeff) - coeff64 = [int64(0)] * n - self.coeff_to_mu(coeff, coeff64) - width = n*self.width + (n - 1)*n//2*self.time_width - packed = [int32(0)] * ((width + 31)//32) - self.pack_coeff_mu(coeff64, packed) - self.set_coeff_mu(packed) - - @kernel(flags={"fast-math"}) - def smooth(self, start: TFloat, stop: TFloat, duration: TFloat, - order: TInt32): - """Initiate an interpolated value change. - - For zeroth order (step) interpolation, the step is at - ``start + duration/2``. - - First order interpolation corresponds to a linear value ramp from - ``start`` to ``stop`` over ``duration``. - - The third order interpolation is constrained to have zero first - order derivative at both `start` and `stop`. - - For first order and third order interpolation (linear and cubic) - the interpolator needs to be stopped explicitly at the stop time - (e.g. by setting spline coefficient data or starting a new - :meth:`smooth` interpolation). - - This method advances the timeline by ``duration``. - - :param start: Initial value of the change. In physical units. - :param stop: Final value of the change. In physical units. - :param duration: Duration of the interpolation. In physical units. - :param order: Order of the interpolation. Only 0, 1, - and 3 are valid: step, linear, cubic. - """ - if order == 0: - delay(duration/2.) - self.set_coeff([stop]) - delay(duration/2.) - elif order == 1: - self.set_coeff([start, (stop - start)/duration]) - delay(duration) - elif order == 3: - v2 = 6.*(stop - start)/(duration*duration) - self.set_coeff([start, 0., v2, -2.*v2/duration]) - delay(duration) - else: - raise ValueError("Invalid interpolation order. " - "Supported orders are: 0, 1, 3.") diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs deleted file mode 100644 index de32ff2e2..000000000 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ /dev/null @@ -1,549 +0,0 @@ -use board_misoc::{csr, clock}; -use ad9154_reg; - -fn spi_setup(dacno: u8) { - unsafe { - while csr::converter_spi::idle_read() == 0 {} - csr::converter_spi::offline_write(0); - csr::converter_spi::end_write(1); - csr::converter_spi::cs_polarity_write(0b0001); - csr::converter_spi::clk_polarity_write(0); - csr::converter_spi::clk_phase_write(0); - csr::converter_spi::lsb_first_write(0); - csr::converter_spi::half_duplex_write(0); - csr::converter_spi::length_write(24 - 1); - csr::converter_spi::div_write(16 - 2); - csr::converter_spi::cs_write(1 << (csr::CONFIG_CONVERTER_SPI_FIRST_AD9154_CS + dacno as u32)); - } -} - -fn write(addr: u16, data: u8) { - unsafe { - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::data_write( - ((addr as u32) << 16) | ((data as u32) << 8)); - } -} - -fn read(addr: u16) -> u8 { - unsafe { - write((1 << 15) | addr, 0); - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::data_read() as u8 - } -} - -// ad9154 mode 1 -// linerate 5Gbps or 6Gbps -// deviceclock_fpga 125MHz or 150MHz -// deviceclock_dac 500MHz or 600MHz - -struct JESDSettings { - did: u8, - bid: u8, - - l: u8, // lanes - m: u8, // converters - n: u8, // bits/converter - np: u8, // bits/sample - - f: u8, // octets/(lane and frame) - s: u8, // samples/(converter and frame) - k: u8, // frames/multiframe - cs: u8, // control bits/sample - - subclassv: u8, - jesdv: u8 -} - -fn jesd_checksum(settings: &JESDSettings) -> u8 { - let mut r: u8 = 0; - for field in [ - settings.did, - settings.bid, - settings.l - 1, - settings.f - 1, - settings.k - 1, - settings.m - 1, - settings.n - 1, - settings.cs, - settings.np - 1, - settings.subclassv, - settings.s - 1, - settings.jesdv, - ].iter() { - r = r.overflowing_add(*field).0; - } - r -} - -const JESD_SETTINGS: JESDSettings = JESDSettings { - did: 0x5a, - bid: 0x5, - - l: 8, - m: 4, - n: 16, - np: 16, - f: 2, - s: 2, - k: 16, - cs: 0, - - subclassv: 1, - jesdv: 1 -}; - -pub fn reset_and_detect(dacno: u8) -> Result<(), &'static str> { - spi_setup(dacno); - // reset - write(ad9154_reg::SPI_INTFCONFA, - 1*ad9154_reg::SOFTRESET_M | 1*ad9154_reg::SOFTRESET | - 0*ad9154_reg::LSBFIRST_M | 0*ad9154_reg::LSBFIRST | - 0*ad9154_reg::ADDRINC_M | 0*ad9154_reg::ADDRINC | - 1*ad9154_reg::SDOACTIVE_M | 1*ad9154_reg::SDOACTIVE); - clock::spin_us(100); - write(ad9154_reg::SPI_INTFCONFA, - 0*ad9154_reg::SOFTRESET_M | 0*ad9154_reg::SOFTRESET | - 0*ad9154_reg::LSBFIRST_M | 0*ad9154_reg::LSBFIRST | - 0*ad9154_reg::ADDRINC_M | 0*ad9154_reg::ADDRINC | - 1*ad9154_reg::SDOACTIVE_M | 1*ad9154_reg::SDOACTIVE); - clock::spin_us(100); - if (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16) != 0x9154 { - return Err("invalid AD9154 identification"); - } else { - info!("AD9154-{} found", dacno); - } - Ok(()) -} - -pub fn setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { - spi_setup(dacno); - info!("AD9154-{} initializing...", dacno); - write(ad9154_reg::PWRCNTRL0, - 0*ad9154_reg::PD_DAC0 | 0*ad9154_reg::PD_DAC1 | - 0*ad9154_reg::PD_DAC2 | 0*ad9154_reg::PD_DAC3 | - 0*ad9154_reg::PD_BG); - clock::spin_us(100); - write(ad9154_reg::TXENMASK1, 0*ad9154_reg::DACA_MASK | - 0*ad9154_reg::DACB_MASK); // DAC PD not controlled by TXEN pins - write(ad9154_reg::PWRCNTRL3, 1*ad9154_reg::ENA_SPI_TXEN | - 1*ad9154_reg::SPI_TXEN); - write(ad9154_reg::CLKCFG0, - 0*ad9154_reg::REF_CLKDIV_EN | 1*ad9154_reg::RF_SYNC_EN | - 1*ad9154_reg::DUTY_EN | 0*ad9154_reg::PD_CLK_REC | - 0*ad9154_reg::PD_SERDES_PCLK | 0*ad9154_reg::PD_CLK_DIG | - 0*ad9154_reg::PD_CLK23 | 0*ad9154_reg::PD_CLK01); - write(ad9154_reg::DACPLLCNTRL, - 0*ad9154_reg::ENABLE_DACPLL | 0*ad9154_reg::RECAL_DACPLL); - write(ad9154_reg::SYSREF_ACTRL0, // jesd204b subclass 1 - 0*ad9154_reg::HYS_CNTRL1 | 0*ad9154_reg::SYSREF_RISE | - 0*ad9154_reg::HYS_ON | 0*ad9154_reg::PD_SYSREF_BUFFER); - - write(ad9154_reg::DEVICE_CONFIG_REG_0, 0x8b); // magic - write(ad9154_reg::DEVICE_CONFIG_REG_1, 0x01); // magic - write(ad9154_reg::DEVICE_CONFIG_REG_2, 0x01); // magic - - write(ad9154_reg::SPI_PAGEINDX, 0x3); // A and B dual - - write(ad9154_reg::INTERP_MODE, 0x03); // 4x - write(ad9154_reg::MIX_MODE, 0); - write(ad9154_reg::DATA_FORMAT, 0*ad9154_reg::BINARY_FORMAT); // s16 - write(ad9154_reg::DATAPATH_CTRL, - 0*ad9154_reg::I_TO_Q | 0*ad9154_reg::SEL_SIDEBAND | - 0*ad9154_reg::MODULATION_TYPE | 0*ad9154_reg::PHASE_ADJ_ENABLE | - 1*ad9154_reg::DIG_GAIN_ENABLE | 0*ad9154_reg::INVSINC_ENABLE); - write(ad9154_reg::IDAC_DIG_GAIN0, 0x00); - write(ad9154_reg::IDAC_DIG_GAIN1, 0x8); - write(ad9154_reg::QDAC_DIG_GAIN0, 0x00); - write(ad9154_reg::QDAC_DIG_GAIN1, 0x8); - write(ad9154_reg::DC_OFFSET_CTRL, 0); - write(ad9154_reg::IPATH_DC_OFFSET_1PART0, 0x00); - write(ad9154_reg::IPATH_DC_OFFSET_1PART1, 0x00); - write(ad9154_reg::IPATH_DC_OFFSET_2PART, 0x00); - write(ad9154_reg::QPATH_DC_OFFSET_1PART0, 0x00); - write(ad9154_reg::QPATH_DC_OFFSET_1PART1, 0x00); - write(ad9154_reg::QPATH_DC_OFFSET_2PART, 0x00); - write(ad9154_reg::PHASE_ADJ0, 0); - write(ad9154_reg::PHASE_ADJ1, 0); - write(ad9154_reg::GROUP_DLY, 0x8*ad9154_reg::COARSE_GROUP_DELAY | - 0x8*ad9154_reg::GROUP_DELAY_RESERVED); - write(ad9154_reg::GROUPDELAY_COMP_BYP, - 1*ad9154_reg::GROUPCOMP_BYPQ | - 1*ad9154_reg::GROUPCOMP_BYPI); - write(ad9154_reg::GROUPDELAY_COMP_I, 0); - write(ad9154_reg::GROUPDELAY_COMP_Q, 0); - write(ad9154_reg::PDP_AVG_TIME, 0*ad9154_reg::PDP_ENABLE); - - write(ad9154_reg::MASTER_PD, 0); - write(ad9154_reg::PHY_PD, 0x00); // lanes 0-7 enabled - write(ad9154_reg::GENERIC_PD, - 0*ad9154_reg::PD_SYNCOUT0B | - 1*ad9154_reg::PD_SYNCOUT1B); - write(ad9154_reg::GENERAL_JRX_CTRL_0, - 0x0*ad9154_reg::LINK_EN | 0*ad9154_reg::LINK_PAGE | - 0*ad9154_reg::LINK_MODE | 0*ad9154_reg::CHECKSUM_MODE); - write(ad9154_reg::ILS_DID, JESD_SETTINGS.did); - write(ad9154_reg::ILS_BID, JESD_SETTINGS.bid); - write(ad9154_reg::ILS_LID0, 0x00); // lane id - write(ad9154_reg::ILS_SCR_L, - (JESD_SETTINGS.l - 1)*ad9154_reg::L_1 | - 1*ad9154_reg::SCR); - write(ad9154_reg::ILS_F, JESD_SETTINGS.f - 1); - write(ad9154_reg::ILS_K, JESD_SETTINGS.k - 1); - write(ad9154_reg::ILS_M, JESD_SETTINGS.m - 1); - write(ad9154_reg::ILS_CS_N, - (JESD_SETTINGS.n - 1)*ad9154_reg::N_1 | - 0*ad9154_reg::CS); - write(ad9154_reg::ILS_NP, - (JESD_SETTINGS.np - 1)*ad9154_reg::NP_1 | - JESD_SETTINGS.subclassv*ad9154_reg::SUBCLASSV); - write(ad9154_reg::ILS_S, - (JESD_SETTINGS.s - 1)*ad9154_reg::S_1 | - JESD_SETTINGS.jesdv*ad9154_reg::JESDV); - write(ad9154_reg::ILS_HD_CF, - 0*ad9154_reg::HD | 0*ad9154_reg::CF); - write(ad9154_reg::ILS_CHECKSUM, jesd_checksum(&JESD_SETTINGS)); - write(ad9154_reg::LANEDESKEW, 0xff); - for i in 0..8 { - write(ad9154_reg::BADDISPARITY, 0*ad9154_reg::RST_IRQ_DIS | - 0*ad9154_reg::DISABLE_ERR_CNTR_DIS | - 1*ad9154_reg::RST_ERR_CNTR_DIS | i*ad9154_reg::LANE_ADDR_DIS); - write(ad9154_reg::BADDISPARITY, 0*ad9154_reg::RST_IRQ_DIS | - 0*ad9154_reg::DISABLE_ERR_CNTR_DIS | - 0*ad9154_reg::RST_ERR_CNTR_DIS | i*ad9154_reg::LANE_ADDR_DIS); - write(ad9154_reg::NIT_W, 0*ad9154_reg::RST_IRQ_NIT | - 0*ad9154_reg::DISABLE_ERR_CNTR_NIT | - 1*ad9154_reg::RST_ERR_CNTR_NIT | i*ad9154_reg::LANE_ADDR_NIT); - write(ad9154_reg::NIT_W, 0*ad9154_reg::RST_IRQ_NIT | - 0*ad9154_reg::DISABLE_ERR_CNTR_NIT | - 0*ad9154_reg::RST_ERR_CNTR_NIT | i*ad9154_reg::LANE_ADDR_NIT); - write(ad9154_reg::UNEXPECTEDCONTROL_W, 0*ad9154_reg::RST_IRQ_UCC | - 0*ad9154_reg::DISABLE_ERR_CNTR_UCC | - 1*ad9154_reg::RST_ERR_CNTR_UCC | i*ad9154_reg::LANE_ADDR_UCC); - write(ad9154_reg::BADDISPARITY, 0*ad9154_reg::RST_IRQ_UCC | - 0*ad9154_reg::DISABLE_ERR_CNTR_UCC | - 0*ad9154_reg::RST_ERR_CNTR_UCC | i*ad9154_reg::LANE_ADDR_UCC); - } - write(ad9154_reg::CTRLREG1, JESD_SETTINGS.f); - write(ad9154_reg::CTRLREG2, 0*ad9154_reg::ILAS_MODE | - 0*ad9154_reg::THRESHOLD_MASK_EN); - write(ad9154_reg::KVAL, 1); // *4*K multiframes during ILAS - write(ad9154_reg::LANEENABLE, 0xff); // CGS _after_ this - - write(ad9154_reg::TERM_BLK1_CTRLREG0, 1); - write(ad9154_reg::TERM_BLK2_CTRLREG0, 1); - write(ad9154_reg::SERDES_SPI_REG, 1); - if linerate > 5_650_000_000 { - write(ad9154_reg::CDR_OPERATING_MODE_REG_0, - 0*ad9154_reg::CDR_OVERSAMP | 0x2*ad9154_reg::CDR_RESERVED | - 1*ad9154_reg::ENHALFRATE); - } else { - write(ad9154_reg::CDR_OPERATING_MODE_REG_0, - 0*ad9154_reg::CDR_OVERSAMP | 0x2*ad9154_reg::CDR_RESERVED | - 0*ad9154_reg::ENHALFRATE); - } - write(ad9154_reg::CDR_RESET, 0); - write(ad9154_reg::CDR_RESET, 1); - if linerate > 5_650_000_000 { - write(ad9154_reg::REF_CLK_DIVIDER_LDO, - 0*ad9154_reg::SPI_CDR_OVERSAMP | - 1*ad9154_reg::SPI_LDO_BYPASS_FILT | - 0*ad9154_reg::SPI_LDO_REF_SEL); - } else { - write(ad9154_reg::REF_CLK_DIVIDER_LDO, - 1*ad9154_reg::SPI_CDR_OVERSAMP | - 1*ad9154_reg::SPI_LDO_BYPASS_FILT | - 0*ad9154_reg::SPI_LDO_REF_SEL); - } - write(ad9154_reg::LDO_FILTER_1, 0x62); // magic - write(ad9154_reg::LDO_FILTER_2, 0xc9); // magic - write(ad9154_reg::LDO_FILTER_3, 0x0e); // magic - write(ad9154_reg::CP_CURRENT_SPI, - 0x12*ad9154_reg::SPI_CP_CURRENT | - 0*ad9154_reg::SPI_SERDES_LOGEN_POWER_MODE); - write(ad9154_reg::VCO_LDO, 0x7b); // magic - write(ad9154_reg::PLL_RD_REG, - 0*ad9154_reg::SPI_SERDES_LOGEN_PD_CORE | - 0*ad9154_reg::SPI_SERDES_LDO_PD | 0*ad9154_reg::SPI_SYN_PD | - 0*ad9154_reg::SPI_VCO_PD_ALC | 0*ad9154_reg::SPI_VCO_PD_PTAT | - 0*ad9154_reg::SPI_VCO_PD); - write(ad9154_reg::ALC_VARACTOR, - 0x9*ad9154_reg::SPI_VCO_VARACTOR | - 0x8*ad9154_reg::SPI_INIT_ALC_VALUE); - write(ad9154_reg::VCO_OUTPUT, - 0xc*ad9154_reg::SPI_VCO_OUTPUT_LEVEL | - 0x4*ad9154_reg::SPI_VCO_OUTPUT_RESERVED); - write(ad9154_reg::CP_CONFIG, - 0*ad9154_reg::SPI_CP_TEST | - 1*ad9154_reg::SPI_CP_CAL_EN | - 0*ad9154_reg::SPI_CP_FORCE_CALBITS | - 0*ad9154_reg::SPI_CP_OFFSET_OFF | - 1*ad9154_reg::SPI_CP_ENABLE_MACHINE | - 0*ad9154_reg::SPI_CP_DITHER_MODE | - 0*ad9154_reg::SPI_CP_HALF_VCO_CAL_CLK); - write(ad9154_reg::VCO_BIAS_1, - 0x3*ad9154_reg::SPI_VCO_BIAS_REF | - 0x3*ad9154_reg::SPI_VCO_BIAS_TCF); - write(ad9154_reg::VCO_BIAS_2, - 0x1*ad9154_reg::SPI_PRESCALE_BIAS | - 1*ad9154_reg::SPI_LAST_ALC_EN | - 0x1*ad9154_reg::SPI_PRESCALE_BYPASS_R | - 0*ad9154_reg::SPI_VCO_COMP_BYPASS_BIASR | - 0*ad9154_reg::SPI_VCO_BYPASS_DAC_R); - write(ad9154_reg::VCO_PD_OVERRIDES, - 0*ad9154_reg::SPI_VCO_PD_OVERRIDE_VCO_BUF | - 1*ad9154_reg::SPI_VCO_PD_OVERRIDE_CAL_TCF | - 0*ad9154_reg::SPI_VCO_PD_OVERRIDE_VAR_REF_TCF | - 0*ad9154_reg::SPI_VCO_PD_OVERRIDE_VAR_REF); - write(ad9154_reg::VCO_CAL, - 0x2*ad9154_reg::SPI_FB_CLOCK_ADV | - 0x3*ad9154_reg::SPI_VCO_CAL_COUNT | - 0*ad9154_reg::SPI_VCO_CAL_ALC_WAIT | - 1*ad9154_reg::SPI_VCO_CAL_EN); - write(ad9154_reg::CP_LEVEL_DETECT, - 0x2*ad9154_reg::SPI_CP_LEVEL_THRESHOLD_HIGH | - 0x5*ad9154_reg::SPI_CP_LEVEL_THRESHOLD_LOW | - 0*ad9154_reg::SPI_CP_LEVEL_DET_PD); - write(ad9154_reg::VCO_VARACTOR_CTRL_0, - 0xe*ad9154_reg::SPI_VCO_VARACTOR_OFFSET | - 0x7*ad9154_reg::SPI_VCO_VARACTOR_REF_TCF); - write(ad9154_reg::VCO_VARACTOR_CTRL_1, - 0x6*ad9154_reg::SPI_VCO_VARACTOR_REF); - // ensure link is txing - //write(ad9154_reg::SERDESPLL_ENABLE_CNTRL, - // 1*ad9154_reg::ENABLE_SERDESPLL | 1*ad9154_reg::RECAL_SERDESPLL) - write(ad9154_reg::SERDESPLL_ENABLE_CNTRL, - 1*ad9154_reg::ENABLE_SERDESPLL | 0*ad9154_reg::RECAL_SERDESPLL); - let t = clock::get_ms(); - while read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB == 0 { - if clock::get_ms() > t + 200 { - return Err("SERDES PLL lock timeout"); - } - } - - write(ad9154_reg::EQ_BIAS_REG, 0x22*ad9154_reg::EQ_BIAS_RESERVED | - 1*ad9154_reg::EQ_POWER_MODE); - - write(ad9154_reg::GENERAL_JRX_CTRL_1, 1); // subclass 1 - write(ad9154_reg::LMFC_DELAY_0, 0); - write(ad9154_reg::LMFC_DELAY_1, 0); - write(ad9154_reg::LMFC_VAR_0, 0x0a); // receive buffer delay - write(ad9154_reg::LMFC_VAR_1, 0x0a); - write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock - // datasheet seems to say ENABLE and ARM should be separate steps, - // so enable now so it can be armed in sync(). - write(ad9154_reg::SYNC_CONTROL, - 0x1*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | - 0*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY); - - write(ad9154_reg::XBAR_LN_0_1, - 0*ad9154_reg::LOGICAL_LANE0_SRC | 1*ad9154_reg::LOGICAL_LANE1_SRC); - write(ad9154_reg::XBAR_LN_2_3, - 2*ad9154_reg::LOGICAL_LANE2_SRC | 3*ad9154_reg::LOGICAL_LANE3_SRC); - write(ad9154_reg::XBAR_LN_4_5, - 4*ad9154_reg::LOGICAL_LANE4_SRC | 5*ad9154_reg::LOGICAL_LANE5_SRC); - write(ad9154_reg::XBAR_LN_6_7, - 6*ad9154_reg::LOGICAL_LANE6_SRC | 7*ad9154_reg::LOGICAL_LANE7_SRC); - write(ad9154_reg::JESD_BIT_INVERSE_CTRL, 0x00); - write(ad9154_reg::GENERAL_JRX_CTRL_0, - 0x1*ad9154_reg::LINK_EN | 0*ad9154_reg::LINK_PAGE | - 0*ad9154_reg::LINK_MODE | 0*ad9154_reg::CHECKSUM_MODE); - info!(" ...done"); - Ok(()) -} - -pub fn status(dacno: u8) { - spi_setup(dacno); - info!("Printing status of AD9154-{}", dacno); - info!("PRODID: 0x{:04x}", (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16)); - info!("SERDES_PLL_LOCK: {}", - (read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB)); - info!(""); - info!("CODEGRPSYNC: 0x{:02x}", read(ad9154_reg::CODEGRPSYNCFLG)); - info!("FRAMESYNC: 0x{:02x}", read(ad9154_reg::FRAMESYNCFLG)); - info!("GOODCHECKSUM: 0x{:02x}", read(ad9154_reg::GOODCHKSUMFLG)); - info!("INITLANESYNC: 0x{:02x}", read(ad9154_reg::INITLANESYNCFLG)); - info!(""); - info!("DID_REG: 0x{:02x}", read(ad9154_reg::DID_REG)); - info!("BID_REG: 0x{:02x}", read(ad9154_reg::BID_REG)); - info!("SCR_L_REG: 0x{:02x}", read(ad9154_reg::SCR_L_REG)); - info!("F_REG: 0x{:02x}", read(ad9154_reg::F_REG)); - info!("K_REG: 0x{:02x}", read(ad9154_reg::K_REG)); - info!("M_REG: 0x{:02x}", read(ad9154_reg::M_REG)); - info!("CS_N_REG: 0x{:02x}", read(ad9154_reg::CS_N_REG)); - info!("NP_REG: 0x{:02x}", read(ad9154_reg::NP_REG)); - info!("S_REG: 0x{:02x}", read(ad9154_reg::S_REG)); - info!("HD_CF_REG: 0x{:02x}", read(ad9154_reg::HD_CF_REG)); - info!("RES1_REG: 0x{:02x}", read(ad9154_reg::RES1_REG)); - info!("RES2_REG: 0x{:02x}", read(ad9154_reg::RES2_REG)); - info!("LIDx_REG: 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}", - read(ad9154_reg::LID0_REG), - read(ad9154_reg::LID1_REG), - read(ad9154_reg::LID2_REG), - read(ad9154_reg::LID3_REG), - read(ad9154_reg::LID4_REG), - read(ad9154_reg::LID5_REG), - read(ad9154_reg::LID6_REG), - read(ad9154_reg::LID7_REG)); - info!("CHECKSUMx_REG: 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}", - read(ad9154_reg::CHECKSUM0_REG), - read(ad9154_reg::CHECKSUM1_REG), - read(ad9154_reg::CHECKSUM2_REG), - read(ad9154_reg::CHECKSUM3_REG), - read(ad9154_reg::CHECKSUM4_REG), - read(ad9154_reg::CHECKSUM5_REG), - read(ad9154_reg::CHECKSUM6_REG), - read(ad9154_reg::CHECKSUM7_REG)); - info!("COMPSUMx_REG: 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}", - read(ad9154_reg::COMPSUM0_REG), - read(ad9154_reg::COMPSUM1_REG), - read(ad9154_reg::COMPSUM2_REG), - read(ad9154_reg::COMPSUM3_REG), - read(ad9154_reg::COMPSUM4_REG), - read(ad9154_reg::COMPSUM5_REG), - read(ad9154_reg::COMPSUM6_REG), - read(ad9154_reg::COMPSUM7_REG)); - info!("BADDISPARITY: 0x{:02x}", read(ad9154_reg::BADDISPARITY)); - info!("NITDISPARITY: 0x{:02x}", read(ad9154_reg::NIT_W)); -} - -pub fn prbs(dacno: u8) -> Result<(), &'static str> { - let mut prbs_errors: u32 = 0; - spi_setup(dacno); - - /* follow phy prbs testing (p58 of ad9154 datasheet) */ - info!("AD9154-{} running PRBS test...", dacno); - - /* step 2: select prbs mode */ - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); - - /* step 3: enable test for all lanes */ - write(ad9154_reg::PHY_PRBS_TEST_EN, 0xff); - - /* step 4: reset */ - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL | - 1*ad9154_reg::PHY_TEST_RESET); - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); - - /* step 5: prbs threshold */ - write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_LOBITS, 0); - write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_MIDBITS, 0); - write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_HIBITS, 0); - - /* step 6: start */ - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL | - 1*ad9154_reg::PHY_TEST_START); - - /* step 7: wait 500 ms */ - clock::spin_us(500000); - - /* step 8 : stop */ - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); - - for i in 0..8 { - /* step 9.a: select src err */ - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - i*ad9154_reg::PHY_SRC_ERR_CNT); - /* step 9.b: retrieve number of errors */ - let lane_errors = (read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_LOBITS) as u32) | - ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_MIDBITS) as u32) << 8) | - ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_HIBITS) as u32) << 16); - if lane_errors > 0 { - warn!(" PRBS errors on lane{}: {:06x}", i, lane_errors); - } - prbs_errors += lane_errors - } - - if prbs_errors > 0 { - return Err("PRBS failed") - } - info!(" ...passed"); - Ok(()) -} - -pub fn stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> { - spi_setup(dacno); - - info!("AD9154-{} running STPL test...", dacno); - - fn prng(seed: u32) -> u32 { - return ((seed + 1)*0x31415979 + 1) & 0xffff; - } - - for i in 0..m { - let mut data: u32; - let mut errors: u8 = 0; - for j in 0..s { - /* select converter */ - write(ad9154_reg::SHORT_TPL_TEST_0, - 0b0*ad9154_reg::SHORT_TPL_TEST_EN | - 0b0*ad9154_reg::SHORT_TPL_TEST_RESET | - i*ad9154_reg::SHORT_TPL_DAC_SEL | - j*ad9154_reg::SHORT_TPL_SP_SEL); - - /* set expected value */ - data = prng(((i as u32) << 8) | (j as u32)); - write(ad9154_reg::SHORT_TPL_TEST_1, (data & 0x00ff) as u8); - write(ad9154_reg::SHORT_TPL_TEST_2, ((data & 0xff00) >> 8) as u8); - - /* enable stpl */ - write(ad9154_reg::SHORT_TPL_TEST_0, - 0b1*ad9154_reg::SHORT_TPL_TEST_EN | - 0b0*ad9154_reg::SHORT_TPL_TEST_RESET | - i*ad9154_reg::SHORT_TPL_DAC_SEL | - j*ad9154_reg::SHORT_TPL_SP_SEL); - - /* reset stpl */ - write(ad9154_reg::SHORT_TPL_TEST_0, - 0b1*ad9154_reg::SHORT_TPL_TEST_EN | - 0b1*ad9154_reg::SHORT_TPL_TEST_RESET | - i*ad9154_reg::SHORT_TPL_DAC_SEL | - j*ad9154_reg::SHORT_TPL_SP_SEL); - - /* release reset stpl */ - write(ad9154_reg::SHORT_TPL_TEST_0, - 0b1*ad9154_reg::SHORT_TPL_TEST_EN | - 0b0*ad9154_reg::SHORT_TPL_TEST_RESET | - i*ad9154_reg::SHORT_TPL_DAC_SEL | - j*ad9154_reg::SHORT_TPL_SP_SEL); - errors += read(ad9154_reg::SHORT_TPL_TEST_3); - } - info!(" c{} errors: {}", i, errors); - if errors > 0 { - return Err("STPL failed") - } - } - - info!(" ...passed"); - Ok(()) -} - -pub fn sync(dacno: u8) -> Result { - spi_setup(dacno); - - write(ad9154_reg::SYNC_CONTROL, - 0x1*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | - 1*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY); - clock::spin_us(1000); // ensure at least one sysref edge - let sync_status = read(ad9154_reg::SYNC_STATUS); - - if sync_status & ad9154_reg::SYNC_BUSY != 0 { - return Err("sync logic busy"); - } - if sync_status & ad9154_reg::SYNC_LOCK == 0 { - return Err("no sync lock"); - } - if sync_status & ad9154_reg::SYNC_TRIP == 0 { - return Err("no sysref edge"); - } - let realign_occured = sync_status & ad9154_reg::SYNC_ROTATE != 0; - Ok(realign_occured) -} diff --git a/artiq/firmware/libboard_artiq/ad9154_reg.rs b/artiq/firmware/libboard_artiq/ad9154_reg.rs deleted file mode 100644 index 3af180496..000000000 --- a/artiq/firmware/libboard_artiq/ad9154_reg.rs +++ /dev/null @@ -1,826 +0,0 @@ -#![allow(dead_code)] - -pub const SPI_INTFCONFA : u16 = 0x000; -pub const SOFTRESET : u8 = 1 << 0; -pub const LSBFIRST : u8 = 1 << 1; -pub const ADDRINC : u8 = 1 << 2; -pub const SDOACTIVE : u8 = 1 << 3; -pub const SDOACTIVE_M : u8 = 1 << 4; -pub const ADDRINC_M : u8 = 1 << 5; -pub const LSBFIRST_M : u8 = 1 << 6; -pub const SOFTRESET_M : u8 = 1 << 7; - -pub const CHIPTYPE : u16 = 0x003; - -pub const PRODIDL : u16 = 0x004; - -pub const PRODIDH : u16 = 0x005; - -pub const CHIPGRADE : u16 = 0x006; -pub const DEV_REVISION : u8 = 1 << 0; -pub const PROD_GRADE : u8 = 1 << 4; - -pub const SPI_PAGEINDX : u16 = 0x008; - -pub const PWRCNTRL0 : u16 = 0x011; -pub const PD_DAC3 : u8 = 1 << 3; -pub const PD_DAC2 : u8 = 1 << 4; -pub const PD_DAC1 : u8 = 1 << 5; -pub const PD_DAC0 : u8 = 1 << 6; -pub const PD_BG : u8 = 1 << 7; - -pub const TXENMASK1 : u16 = 0x012; -pub const DACA_MASK : u8 = 1 << 6; -pub const DACB_MASK : u8 = 1 << 7; - -pub const PWRCNTRL3 : u16 = 0x013; -pub const SPI_TXEN : u8 = 1 << 0; -pub const ENA_SPI_TXEN : u8 = 1 << 1; -pub const SPI_PA_CTRL : u8 = 1 << 2; -pub const ENA_PA_CTRL_FROM_SPI : u8 = 1 << 3; -pub const ENA_PA_CTRL_FROM_BLSM : u8 = 1 << 4; -pub const ENA_PA_CTRL_FROM_TXENSM : u8 = 1 << 5; -pub const ENA_PA_CTRL_FROM_PARROT_ERR : u8 = 1 << 6; - -pub const GROUP_DLY : u16 = 0x014; -pub const COARSE_GROUP_DELAY : u8 = 1 << 0; -pub const GROUP_DELAY_RESERVED : u8 = 1 << 4; - -pub const IRQEN_STATUSMODE0 : u16 = 0x01f; -pub const IRQEN_SMODE_LANEFIFOERR : u8 = 1 << 1; -pub const IRQEN_SMODE_SERPLLLOCK : u8 = 1 << 2; -pub const IRQEN_SMODE_SERPLLLOST : u8 = 1 << 3; -pub const IRQEN_SMODE_DACPLLLOCK : u8 = 1 << 4; -pub const IRQEN_SMODE_DACPLLLOST : u8 = 1 << 5; - -pub const IRQEN_STATUSMODE1 : u16 = 0x020; -pub const IRQEN_SMODE_PRBS0 : u8 = 1 << 0; -pub const IRQEN_SMODE_PRBS1 : u8 = 1 << 1; -pub const IRQEN_SMODE_PRBS2 : u8 = 1 << 2; -pub const IRQEN_SMODE_PRBS3 : u8 = 1 << 3; - -pub const IRQEN_STATUSMODE2 : u16 = 0x021; -pub const IRQEN_SMODE_SYNC_TRIP0 : u8 = 1 << 0; -pub const IRQEN_SMODE_SYNC_WLIM0 : u8 = 1 << 1; -pub const IRQEN_SMODE_SYNC_ROTATE0 : u8 = 1 << 2; -pub const IRQEN_SMODE_SYNC_LOCK0 : u8 = 1 << 3; -pub const IRQEN_SMODE_NCO_ALIGN0 : u8 = 1 << 4; -pub const IRQEN_SMODE_BLNKDONE0 : u8 = 1 << 5; -pub const IRQEN_SMODE_PDPERR0 : u8 = 1 << 7; - -pub const IRQEN_STATUSMODE3 : u16 = 0x022; -pub const IRQEN_SMODE_SYNC_TRIP1 : u8 = 1 << 0; -pub const IRQEN_SMODE_SYNC_WLIM1 : u8 = 1 << 1; -pub const IRQEN_SMODE_SYNC_ROTATE1 : u8 = 1 << 2; -pub const IRQEN_SMODE_SYNC_LOCK1 : u8 = 1 << 3; -pub const IRQEN_SMODE_NCO_ALIGN1 : u8 = 1 << 4; -pub const IRQEN_SMODE_BLNKDONE1 : u8 = 1 << 5; -pub const IRQEN_SMODE_PDPERR1 : u8 = 1 << 7; - -pub const IRQ_STATUS0 : u16 = 0x023; -pub const LANEFIFOERR : u8 = 1 << 1; -pub const SERPLLLOCK : u8 = 1 << 2; -pub const SERPLLLOST : u8 = 1 << 3; -pub const DACPLLLOCK : u8 = 1 << 4; -pub const DACPLLLOST : u8 = 1 << 5; - -pub const IRQ_STATUS1 : u16 = 0x024; -pub const PRBS0 : u8 = 1 << 0; -pub const PRBS1 : u8 = 1 << 1; -pub const PRBS2 : u8 = 1 << 2; -pub const PRBS3 : u8 = 1 << 3; - -pub const IRQ_STATUS2 : u16 = 0x025; -pub const SYNC_TRIP0 : u8 = 1 << 0; -pub const SYNC_WLIM0 : u8 = 1 << 1; -pub const SYNC_ROTATE0 : u8 = 1 << 2; -pub const SYNC_LOCK0 : u8 = 1 << 3; -pub const NCO_ALIGN0 : u8 = 1 << 4; -pub const BLNKDONE0 : u8 = 1 << 5; -pub const PDPERR0 : u8 = 1 << 7; - -pub const IRQ_STATUS3 : u16 = 0x026; -pub const SYNC_TRIP1 : u8 = 1 << 0; -pub const SYNC_WLIM1 : u8 = 1 << 1; -pub const SYNC_ROTATE1 : u8 = 1 << 2; -pub const SYNC_LOCK1 : u8 = 1 << 3; -pub const NCO_ALIGN1 : u8 = 1 << 4; -pub const BLNKDONE1 : u8 = 1 << 5; -pub const PDPERR1 : u8 = 1 << 7; - -pub const JESD_CHECKS : u16 = 0x030; -pub const ERR_INTSUPP : u8 = 1 << 0; -pub const ERR_SUBCLASS : u8 = 1 << 1; -pub const ERR_KUNSUPP : u8 = 1 << 2; -pub const ERR_JESDBAD : u8 = 1 << 3; -pub const ERR_WINLIMIT : u8 = 1 << 4; -pub const ERR_DLYOVER : u8 = 1 << 5; - -pub const SYNC_ERRWINDOW : u16 = 0x034; - -pub const SYNC_LASTERR_L : u16 = 0x038; - -pub const SYNC_LASTERR_H : u16 = 0x039; -pub const LASTERROR_H : u8 = 1 << 0; -pub const LASTOVER : u8 = 1 << 6; -pub const LASTUNDER : u8 = 1 << 7; - -pub const SYNC_CONTROL : u16 = 0x03a; -pub const SYNCMODE : u8 = 1 << 0; -pub const SYNCCLRLAST : u8 = 1 << 4; -pub const SYNCCLRSTKY : u8 = 1 << 5; -pub const SYNCARM : u8 = 1 << 6; -pub const SYNCENABLE : u8 = 1 << 7; - -pub const SYNC_STATUS : u16 = 0x03b; -pub const SYNC_TRIP : u8 = 1 << 0; -pub const SYNC_WLIM : u8 = 1 << 1; -pub const SYNC_ROTATE : u8 = 1 << 2; -pub const SYNC_LOCK : u8 = 1 << 3; -pub const SYNC_BUSY : u8 = 1 << 7; - -pub const SYNC_CURRERR_L : u16 = 0x03c; - -pub const SYNC_CURRERR_H : u16 = 0x03d; -pub const CURRERROR_H : u8 = 1 << 0; -pub const CURROVER : u8 = 1 << 6; -pub const CURRUNDER : u8 = 1 << 7; - -pub const DACGAIN0_I : u16 = 0x040; - -pub const DACGAIN1_I : u16 = 0x041; - -pub const DACGAIN0_Q : u16 = 0x042; - -pub const DACGAIN1_Q : u16 = 0x043; - -pub const GROUPDELAY_COMP_I : u16 = 0x044; - -pub const GROUPDELAY_COMP_Q : u16 = 0x045; - -pub const GROUPDELAY_COMP_BYP : u16 = 0x046; -pub const GROUPCOMP_BYPQ : u8 = 1 << 0; -pub const GROUPCOMP_BYPI : u8 = 1 << 1; - -pub const MIX_MODE : u16 = 0x04a; - -pub const NCOALIGN_MODE : u16 = 0x050; -pub const NCO_ALIGN_MODE : u8 = 1 << 0; -pub const NCO_ALIGN_FAIL : u8 = 1 << 3; -pub const NCO_ALIGN_PASS : u8 = 1 << 4; -pub const NCO_ALIGN_MTCH : u8 = 1 << 5; -pub const NCO_ALIGN_ARM : u8 = 1 << 7; - -pub const NCOKEY_ILSB : u16 = 0x051; - -pub const NCOKEY_IMSB : u16 = 0x052; - -pub const NCOKEY_QLSB : u16 = 0x053; - -pub const NCOKEY_QMSB : u16 = 0x054; - -pub const PDP_THRES0 : u16 = 0x060; - -pub const PDP_THRES1 : u16 = 0x061; - -pub const PDP_AVG_TIME : u16 = 0x062; -pub const PDP_AVG_TIME_ : u8 = 1 << 0; -pub const PA_BUS_SWAP : u8 = 1 << 6; -pub const PDP_ENABLE : u8 = 1 << 7; - -pub const PDP_POWER0 : u16 = 0x063; - -pub const PDP_POWER1 : u16 = 0x064; - -pub const CLKCFG0 : u16 = 0x080; -pub const REF_CLKDIV_EN : u8 = 1 << 0; -pub const RF_SYNC_EN : u8 = 1 << 1; -pub const DUTY_EN : u8 = 1 << 2; -pub const PD_CLK_REC : u8 = 1 << 3; -pub const PD_SERDES_PCLK : u8 = 1 << 4; -pub const PD_CLK_DIG : u8 = 1 << 5; -pub const PD_CLK23 : u8 = 1 << 6; -pub const PD_CLK01 : u8 = 1 << 7; - -pub const SYSREF_ACTRL0 : u16 = 0x081; -pub const HYS_CNTRL1 : u8 = 1 << 0; -pub const SYSREF_RISE : u8 = 1 << 2; -pub const HYS_ON : u8 = 1 << 3; -pub const PD_SYSREF_BUFFER : u8 = 1 << 4; - -pub const SYSREF_ACTRL1 : u16 = 0x082; - -pub const DACPLLCNTRL : u16 = 0x083; -pub const ENABLE_DACPLL : u8 = 1 << 4; -pub const RECAL_DACPLL : u8 = 1 << 7; - -pub const DACPLLSTATUS : u16 = 0x084; -pub const DACPLL_LOCK : u8 = 1 << 1; -pub const VCO_CAL_PROGRESS : u8 = 1 << 3; -pub const CP_CAL_VALID : u8 = 1 << 4; -pub const CP_OVERRANGE_L : u8 = 1 << 5; -pub const CP_OVERRANGE_H : u8 = 1 << 6; - -pub const DACINTEGERWORD0 : u16 = 0x085; - -pub const DACLOOPFILT1 : u16 = 0x087; -pub const LF_C1_WORD : u8 = 1 << 0; -pub const LF_C2_WORD : u8 = 1 << 4; - -pub const DACLOOPFILT2 : u16 = 0x088; -pub const LF_C3_WORD : u8 = 1 << 0; -pub const LF_R1_WORD : u8 = 1 << 4; - -pub const DACLOOPFILT3 : u16 = 0x089; -pub const LF_R3_WORD : u8 = 1 << 0; -pub const LF_BYPASS_C1 : u8 = 1 << 4; -pub const LF_BYPASS_C2 : u8 = 1 << 5; -pub const LF_BYPASS_R1 : u8 = 1 << 6; -pub const LF_BYPASS_R3 : u8 = 1 << 7; - -pub const DACCPCNTRL : u16 = 0x08a; -pub const CP_CURRENT : u8 = 1 << 0; -pub const VT_FORCE : u8 = 1 << 6; - -pub const DACLOGENCNTRL : u16 = 0x08b; -pub const LODIVMODE : u8 = 1 << 0; -pub const LO_POWER_MODE : u8 = 1 << 4; - -pub const DACLDOCNTRL1 : u16 = 0x08c; -pub const REFDIVMODE : u8 = 1 << 0; -pub const LDO_BYPASS_FLT : u8 = 1 << 6; -pub const LDO_REF_SEL : u8 = 1 << 7; - -pub const DACLDOCNTRL2 : u16 = 0x08d; -pub const LDO_VDROP : u8 = 1 << 0; -pub const LDO_SEL : u8 = 1 << 2; -pub const LDO_INRUSH : u8 = 1 << 5; -pub const LDO_BYPASS : u8 = 1 << 7; - -pub const DATA_FORMAT : u16 = 0x110; -pub const BINARY_FORMAT : u8 = 1 << 7; - -pub const DATAPATH_CTRL : u16 = 0x111; -pub const I_TO_Q : u8 = 1 << 0; -pub const SEL_SIDEBAND : u8 = 1 << 1; -pub const MODULATION_TYPE : u8 = 1 << 2; -pub const PHASE_ADJ_ENABLE : u8 = 1 << 4; -pub const DIG_GAIN_ENABLE : u8 = 1 << 5; -pub const INVSINC_ENABLE : u8 = 1 << 7; - -pub const INTERP_MODE : u16 = 0x112; - -pub const NCO_FTW_UPDATE : u16 = 0x113; -pub const FTW_UPDATE_REQ : u8 = 1 << 0; -pub const FTW_UPDATE_ACK : u8 = 1 << 1; - -pub const FTW0 : u16 = 0x114; - -pub const FTW1 : u16 = 0x115; - -pub const FTW2 : u16 = 0x116; - -pub const FTW3 : u16 = 0x117; - -pub const FTW4 : u16 = 0x118; - -pub const FTW5 : u16 = 0x119; - -pub const NCO_PHASE_OFFSET0 : u16 = 0x11a; - -pub const NCO_PHASE_OFFSET1 : u16 = 0x11b; - -pub const PHASE_ADJ0 : u16 = 0x11c; - -pub const PHASE_ADJ1 : u16 = 0x11d; - -pub const TXEN_SM_0 : u16 = 0x11f; -pub const TXEN_SM_EN : u8 = 1 << 0; -pub const GP_PA_CTRL : u8 = 1 << 1; -pub const GP_PA_ON_INVERT : u8 = 1 << 2; -pub const RISE_COUNTERS : u8 = 1 << 4; -pub const FALL_COUNTERS : u8 = 1 << 6; - -pub const TXEN_RISE_COUNT_0 : u16 = 0x121; - -pub const TXEN_RISE_COUNT_1 : u16 = 0x122; - -pub const TXEN_FALL_COUNT_0 : u16 = 0x123; - -pub const TXEN_FALL_COUNT_1 : u16 = 0x124; - -pub const DEVICE_CONFIG_REG_0 : u16 = 0x12d; - -pub const DIE_TEMP_CTRL0 : u16 = 0x12f; -pub const AUXADC_ENABLE : u8 = 1 << 0; -pub const AUXADC_RESERVED : u8 = 1 << 1; - -pub const DIE_TEMP0 : u16 = 0x132; - -pub const DIE_TEMP1 : u16 = 0x133; - -pub const DIE_TEMP_UPDATE : u16 = 0x134; - -pub const DC_OFFSET_CTRL : u16 = 0x135; - -pub const IPATH_DC_OFFSET_1PART0 : u16 = 0x136; - -pub const IPATH_DC_OFFSET_1PART1 : u16 = 0x137; - -pub const QPATH_DC_OFFSET_1PART0 : u16 = 0x138; - -pub const QPATH_DC_OFFSET_1PART1 : u16 = 0x139; - -pub const IPATH_DC_OFFSET_2PART : u16 = 0x13a; - -pub const QPATH_DC_OFFSET_2PART : u16 = 0x13b; - -pub const IDAC_DIG_GAIN0 : u16 = 0x13c; - -pub const IDAC_DIG_GAIN1 : u16 = 0x13d; - -pub const QDAC_DIG_GAIN0 : u16 = 0x13e; - -pub const QDAC_DIG_GAIN1 : u16 = 0x13f; - -pub const GAIN_RAMP_UP_STEP0 : u16 = 0x140; - -pub const GAIN_RAMP_UP_STEP1 : u16 = 0x141; - -pub const GAIN_RAMP_DOWN_STEP0 : u16 = 0x142; - -pub const GAIN_RAMP_DOWN_STEP1 : u16 = 0x143; - -pub const DEVICE_CONFIG_REG_1 : u16 = 0x146; - -pub const BSM_STAT : u16 = 0x147; -pub const SOFTBLANKRB : u8 = 1 << 6; - -pub const PRBS : u16 = 0x14b; -pub const PRBS_EN : u8 = 1 << 0; -pub const PRBS_RESET : u8 = 1 << 1; -pub const PRBS_MODE : u8 = 1 << 2; -pub const PRBS_GOOD_I : u8 = 1 << 6; -pub const PRBS_GOOD_Q : u8 = 1 << 7; - -pub const PRBS_ERROR_I : u16 = 0x14c; - -pub const PRBS_ERROR_Q : u16 = 0x14d; - -pub const DACPLLT0 : u16 = 0x1b0; -pub const LOGEN_PD : u8 = 1 << 1; -pub const LDO_PD : u8 = 1 << 3; -pub const SYNTH_PD : u8 = 1 << 4; -pub const VCO_PD_ALC : u8 = 1 << 5; -pub const VCO_PD_PTAT : u8 = 1 << 6; -pub const VCO_PD_IN : u8 = 1 << 7; - -pub const DACPLLT1 : u16 = 0x1b1; -pub const PFD_EDGE : u8 = 1 << 1; -pub const PFD_DELAY : u8 = 1 << 2; - -pub const DACPLLT2 : u16 = 0x1b2; -pub const EXT_ALC_WORD : u8 = 1 << 0; -pub const EXT_ALC_WORD_EN : u8 = 1 << 7; - -pub const DACPLLT3 : u16 = 0x1b3; -pub const EXT_BAND1 : u8 = 1 << 0; - -pub const DACPLLT4 : u16 = 0x1b4; -pub const EXT_BAND2 : u8 = 1 << 0; -pub const EXT_BAND_EN : u8 = 1 << 1; -pub const VCO_CAL_OFFSET : u8 = 1 << 3; -pub const BYP_LOAD_DELAY : u8 = 1 << 7; - -pub const DACPLLT5 : u16 = 0x1b5; - -pub const DACPLLT6 : u16 = 0x1b6; - -pub const DACPLLT7 : u16 = 0x1b7; - -pub const DACPLLT8 : u16 = 0x1b8; - -pub const DACPLLT9 : u16 = 0x1b9; - -pub const DACPLLTA : u16 = 0x1ba; - -pub const DACPLLTB : u16 = 0x1bb; -pub const VCO_BIAS_REF : u8 = 1 << 0; -pub const VCO_BIAS_TCF : u8 = 1 << 3; - -pub const DACPLLTC : u16 = 0x1bc; - -pub const DACPLLTD : u16 = 0x1bd; - -pub const DACPLLTE : u16 = 0x1be; - -pub const DACPLLTF : u16 = 0x1bf; - -pub const DACPLLT10 : u16 = 0x1c0; - -pub const DACPLLT11 : u16 = 0x1c1; - -pub const DACPLLT15 : u16 = 0x1c2; - -pub const DACPLLT16 : u16 = 0x1c3; - -pub const DACPLLT17 : u16 = 0x1c4; - -pub const DACPLLT18 : u16 = 0x1c5; - -pub const MASTER_PD : u16 = 0x200; - -pub const PHY_PD : u16 = 0x201; - -pub const GENERIC_PD : u16 = 0x203; -pub const PD_SYNCOUT1B : u8 = 1 << 0; -pub const PD_SYNCOUT0B : u8 = 1 << 1; - -pub const CDR_RESET : u16 = 0x206; - -pub const CDR_OPERATING_MODE_REG_0 : u16 = 0x230; -pub const CDR_OVERSAMP : u8 = 1 << 1; -pub const CDR_RESERVED : u8 = 1 << 2; -pub const ENHALFRATE : u8 = 1 << 5; - -pub const EQ_BIAS_REG : u16 = 0x268; -pub const EQ_BIAS_RESERVED : u8 = 1 << 0; -pub const EQ_POWER_MODE : u8 = 1 << 6; - -pub const SERDESPLL_ENABLE_CNTRL : u16 = 0x280; -pub const ENABLE_SERDESPLL : u8 = 1 << 0; -pub const RECAL_SERDESPLL : u8 = 1 << 2; - -pub const PLL_STATUS : u16 = 0x281; -pub const SERDES_PLL_LOCK_RB : u8 = 1 << 0; -pub const SERDES_CURRENTS_READY_RB : u8 = 1 << 1; -pub const SERDES_VCO_CAL_IN_PROGRESS_RB : u8 = 1 << 2; -pub const SERDES_PLL_CAL_VALID_RB : u8 = 1 << 3; -pub const SERDES_PLL_OVERRANGE_L_RB : u8 = 1 << 4; -pub const SERDES_PLL_OVERRANGE_H_RB : u8 = 1 << 5; - -pub const LDO_FILTER_1 : u16 = 0x284; - -pub const LDO_FILTER_2 : u16 = 0x285; - -pub const LDO_FILTER_3 : u16 = 0x286; - -pub const CP_CURRENT_SPI : u16 = 0x287; -pub const SPI_CP_CURRENT : u8 = 1 << 0; -pub const SPI_SERDES_LOGEN_POWER_MODE : u8 = 1 << 6; - -pub const REF_CLK_DIVIDER_LDO : u16 = 0x289; -pub const SPI_CDR_OVERSAMP : u8 = 1 << 0; -pub const SPI_LDO_BYPASS_FILT : u8 = 1 << 2; -pub const SPI_LDO_REF_SEL : u8 = 1 << 3; - -pub const VCO_LDO : u16 = 0x28a; - -pub const PLL_RD_REG : u16 = 0x28b; -pub const SPI_SERDES_LOGEN_PD_CORE : u8 = 1 << 0; -pub const SPI_SERDES_LDO_PD : u8 = 1 << 2; -pub const SPI_SYN_PD : u8 = 1 << 3; -pub const SPI_VCO_PD_ALC : u8 = 1 << 4; -pub const SPI_VCO_PD_PTAT : u8 = 1 << 5; -pub const SPI_VCO_PD : u8 = 1 << 6; - -pub const ALC_VARACTOR : u16 = 0x290; -pub const SPI_VCO_VARACTOR : u8 = 1 << 0; -pub const SPI_INIT_ALC_VALUE : u8 = 1 << 4; - -pub const VCO_OUTPUT : u16 = 0x291; -pub const SPI_VCO_OUTPUT_LEVEL : u8 = 1 << 0; -pub const SPI_VCO_OUTPUT_RESERVED : u8 = 1 << 4; - -pub const CP_CONFIG : u16 = 0x294; -pub const SPI_CP_TEST : u8 = 1 << 0; -pub const SPI_CP_CAL_EN : u8 = 1 << 2; -pub const SPI_CP_FORCE_CALBITS : u8 = 1 << 3; -pub const SPI_CP_OFFSET_OFF : u8 = 1 << 4; -pub const SPI_CP_ENABLE_MACHINE : u8 = 1 << 5; -pub const SPI_CP_DITHER_MODE : u8 = 1 << 6; -pub const SPI_CP_HALF_VCO_CAL_CLK : u8 = 1 << 7; - -pub const VCO_BIAS_1 : u16 = 0x296; -pub const SPI_VCO_BIAS_REF : u8 = 1 << 0; -pub const SPI_VCO_BIAS_TCF : u8 = 1 << 3; - -pub const VCO_BIAS_2 : u16 = 0x297; -pub const SPI_PRESCALE_BIAS : u8 = 1 << 0; -pub const SPI_LAST_ALC_EN : u8 = 1 << 2; -pub const SPI_PRESCALE_BYPASS_R : u8 = 1 << 3; -pub const SPI_VCO_COMP_BYPASS_BIASR : u8 = 1 << 4; -pub const SPI_VCO_BYPASS_DAC_R : u8 = 1 << 5; - -pub const VCO_PD_OVERRIDES : u16 = 0x299; -pub const SPI_VCO_PD_OVERRIDE_VCO_BUF : u8 = 1 << 0; -pub const SPI_VCO_PD_OVERRIDE_CAL_TCF : u8 = 1 << 1; -pub const SPI_VCO_PD_OVERRIDE_VAR_REF_TCF : u8 = 1 << 2; -pub const SPI_VCO_PD_OVERRIDE_VAR_REF : u8 = 1 << 3; - -pub const VCO_CAL : u16 = 0x29a; -pub const SPI_FB_CLOCK_ADV : u8 = 1 << 0; -pub const SPI_VCO_CAL_COUNT : u8 = 1 << 2; -pub const SPI_VCO_CAL_ALC_WAIT : u8 = 1 << 4; -pub const SPI_VCO_CAL_EN : u8 = 1 << 7; - -pub const CP_LEVEL_DETECT : u16 = 0x29c; -pub const SPI_CP_LEVEL_THRESHOLD_HIGH : u8 = 1 << 0; -pub const SPI_CP_LEVEL_THRESHOLD_LOW : u8 = 1 << 3; -pub const SPI_CP_LEVEL_DET_PD : u8 = 1 << 6; - -pub const VCO_VARACTOR_CTRL_0 : u16 = 0x29f; -pub const SPI_VCO_VARACTOR_OFFSET : u8 = 1 << 0; -pub const SPI_VCO_VARACTOR_REF_TCF : u8 = 1 << 4; - -pub const VCO_VARACTOR_CTRL_1 : u16 = 0x2a0; -pub const SPI_VCO_VARACTOR_REF : u8 = 1 << 0; - -pub const TERM_BLK1_CTRLREG0 : u16 = 0x2a7; - -pub const TERM_BLK2_CTRLREG0 : u16 = 0x2ae; - -pub const GENERAL_JRX_CTRL_0 : u16 = 0x300; -pub const LINK_EN : u8 = 1 << 0; -pub const LINK_PAGE : u8 = 1 << 2; -pub const LINK_MODE : u8 = 1 << 3; -pub const CHECKSUM_MODE : u8 = 1 << 6; - -pub const GENERAL_JRX_CTRL_1 : u16 = 0x301; - -pub const DYN_LINK_LATENCY_0 : u16 = 0x302; - -pub const DYN_LINK_LATENCY_1 : u16 = 0x303; - -pub const LMFC_DELAY_0 : u16 = 0x304; - -pub const LMFC_DELAY_1 : u16 = 0x305; - -pub const LMFC_VAR_0 : u16 = 0x306; - -pub const LMFC_VAR_1 : u16 = 0x307; - -pub const XBAR_LN_0_1 : u16 = 0x308; -pub const LOGICAL_LANE0_SRC : u8 = 1 << 0; -pub const LOGICAL_LANE1_SRC : u8 = 1 << 3; - -pub const XBAR_LN_2_3 : u16 = 0x309; -pub const LOGICAL_LANE2_SRC : u8 = 1 << 0; -pub const LOGICAL_LANE3_SRC : u8 = 1 << 3; - -pub const XBAR_LN_4_5 : u16 = 0x30a; -pub const LOGICAL_LANE4_SRC : u8 = 1 << 0; -pub const LOGICAL_LANE5_SRC : u8 = 1 << 3; - -pub const XBAR_LN_6_7 : u16 = 0x30b; -pub const LOGICAL_LANE6_SRC : u8 = 1 << 0; -pub const LOGICAL_LANE7_SRC : u8 = 1 << 3; - -pub const FIFO_STATUS_REG_0 : u16 = 0x30c; - -pub const FIFO_STATUS_REG_1 : u16 = 0x30d; - -pub const SYNCB_GEN_1 : u16 = 0x312; -pub const SYNCB_ERR_DUR : u8 = 1 << 4; - -pub const SERDES_SPI_REG : u16 = 0x314; - -pub const PHY_PRBS_TEST_EN : u16 = 0x315; - -pub const PHY_PRBS_TEST_CTRL : u16 = 0x316; -pub const PHY_TEST_RESET : u8 = 1 << 0; -pub const PHY_TEST_START : u8 = 1 << 1; -pub const PHY_PRBS_PAT_SEL : u8 = 1 << 2; -pub const PHY_SRC_ERR_CNT : u8 = 1 << 4; - -pub const PHY_PRBS_TEST_THRESHOLD_LOBITS : u16 = 0x317; - -pub const PHY_PRBS_TEST_THRESHOLD_MIDBITS : u16 = 0x318; - -pub const PHY_PRBS_TEST_THRESHOLD_HIBITS : u16 = 0x319; - -pub const PHY_PRBS_TEST_ERRCNT_LOBITS : u16 = 0x31a; - -pub const PHY_PRBS_TEST_ERRCNT_MIDBITS : u16 = 0x31b; - -pub const PHY_PRBS_TEST_ERRCNT_HIBITS : u16 = 0x31c; - -pub const PHY_PRBS_TEST_STATUS : u16 = 0x31d; - -pub const SHORT_TPL_TEST_0 : u16 = 0x32c; -pub const SHORT_TPL_TEST_EN : u8 = 1 << 0; -pub const SHORT_TPL_TEST_RESET : u8 = 1 << 1; -pub const SHORT_TPL_DAC_SEL : u8 = 1 << 2; -pub const SHORT_TPL_SP_SEL : u8 = 1 << 4; - -pub const SHORT_TPL_TEST_1 : u16 = 0x32d; - -pub const SHORT_TPL_TEST_2 : u16 = 0x32e; - -pub const SHORT_TPL_TEST_3 : u16 = 0x32f; - -pub const DEVICE_CONFIG_REG_2 : u16 = 0x333; - -pub const JESD_BIT_INVERSE_CTRL : u16 = 0x334; - -pub const DID_REG : u16 = 0x400; - -pub const BID_REG : u16 = 0x401; -pub const BID_RD : u8 = 1 << 0; -pub const ADJCNT_RD : u8 = 1 << 4; - -pub const LID0_REG : u16 = 0x402; -pub const LID0_RD : u8 = 1 << 0; -pub const PHADJ_RD : u8 = 1 << 5; -pub const ADJDIR_RD : u8 = 1 << 6; - -pub const SCR_L_REG : u16 = 0x403; -pub const L_1_RD : u8 = 1 << 0; -pub const SCR_RD : u8 = 1 << 7; - -pub const F_REG : u16 = 0x404; - -pub const K_REG : u16 = 0x405; - -pub const M_REG : u16 = 0x406; - -pub const CS_N_REG : u16 = 0x407; -pub const N_1_RD : u8 = 1 << 0; -pub const CS_RD : u8 = 1 << 6; - -pub const NP_REG : u16 = 0x408; -pub const NP_1_RD : u8 = 1 << 0; -pub const SUBCLASSV_RD : u8 = 1 << 5; - -pub const S_REG : u16 = 0x409; -pub const S_1_RD : u8 = 1 << 0; -pub const JESDV_RD : u8 = 1 << 5; - -pub const HD_CF_REG : u16 = 0x40a; -pub const CF_RD : u8 = 1 << 0; -pub const HD_RD : u8 = 1 << 7; - -pub const RES1_REG : u16 = 0x40b; - -pub const RES2_REG : u16 = 0x40c; - -pub const CHECKSUM0_REG : u16 = 0x40d; - -pub const COMPSUM0_REG : u16 = 0x40e; - -pub const LID1_REG : u16 = 0x412; - -pub const CHECKSUM1_REG : u16 = 0x415; - -pub const COMPSUM1_REG : u16 = 0x416; - -pub const LID2_REG : u16 = 0x41a; - -pub const CHECKSUM2_REG : u16 = 0x41d; - -pub const COMPSUM2_REG : u16 = 0x41e; - -pub const LID3_REG : u16 = 0x422; - -pub const CHECKSUM3_REG : u16 = 0x425; - -pub const COMPSUM3_REG : u16 = 0x426; - -pub const LID4_REG : u16 = 0x42a; - -pub const CHECKSUM4_REG : u16 = 0x42d; - -pub const COMPSUM4_REG : u16 = 0x42e; - -pub const LID5_REG : u16 = 0x432; - -pub const CHECKSUM5_REG : u16 = 0x435; - -pub const COMPSUM5_REG : u16 = 0x436; - -pub const LID6_REG : u16 = 0x43a; - -pub const CHECKSUM6_REG : u16 = 0x43d; - -pub const COMPSUM6_REG : u16 = 0x43e; - -pub const LID7_REG : u16 = 0x442; - -pub const CHECKSUM7_REG : u16 = 0x445; - -pub const COMPSUM7_REG : u16 = 0x446; - -pub const ILS_DID : u16 = 0x450; - -pub const ILS_BID : u16 = 0x451; -pub const BID : u8 = 1 << 0; -pub const ADJCNT : u8 = 1 << 4; - -pub const ILS_LID0 : u16 = 0x452; -pub const LID0 : u8 = 1 << 0; -pub const PHADJ : u8 = 1 << 5; -pub const ADJDIR : u8 = 1 << 6; - -pub const ILS_SCR_L : u16 = 0x453; -pub const L_1 : u8 = 1 << 0; -pub const SCR : u8 = 1 << 7; - -pub const ILS_F : u16 = 0x454; - -pub const ILS_K : u16 = 0x455; - -pub const ILS_M : u16 = 0x456; - -pub const ILS_CS_N : u16 = 0x457; -pub const N_1 : u8 = 1 << 0; -pub const CS : u8 = 1 << 6; - -pub const ILS_NP : u16 = 0x458; -pub const NP_1 : u8 = 1 << 0; -pub const SUBCLASSV : u8 = 1 << 5; - -pub const ILS_S : u16 = 0x459; -pub const S_1 : u8 = 1 << 0; -pub const JESDV : u8 = 1 << 5; - -pub const ILS_HD_CF : u16 = 0x45a; -pub const CF : u8 = 1 << 0; -pub const HD : u8 = 1 << 7; - -pub const ILS_RES1 : u16 = 0x45b; - -pub const ILS_RES2 : u16 = 0x45c; - -pub const ILS_CHECKSUM : u16 = 0x45d; - -pub const ERRCNTRMON : u16 = 0x46b; -pub const CNTRSEL : u8 = 1 << 0; -pub const LANESEL : u8 = 1 << 4; - -pub const LANEDESKEW : u16 = 0x46c; - -pub const BADDISPARITY : u16 = 0x46d; -pub const LANE_ADDR_DIS : u8 = 1 << 0; -pub const RST_ERR_CNTR_DIS : u8 = 1 << 5; -pub const DISABLE_ERR_CNTR_DIS : u8 = 1 << 6; -pub const RST_IRQ_DIS : u8 = 1 << 7; - -pub const NIT_W : u16 = 0x46e; -pub const LANE_ADDR_NIT : u8 = 1 << 0; -pub const RST_ERR_CNTR_NIT : u8 = 1 << 5; -pub const DISABLE_ERR_CNTR_NIT : u8 = 1 << 6; -pub const RST_IRQ_NIT : u8 = 1 << 7; - -pub const UNEXPECTEDCONTROL_W : u16 = 0x46f; -pub const LANE_ADDR_UCC : u8 = 1 << 0; -pub const RST_ERR_CNTR_UCC : u8 = 1 << 5; -pub const DISABLE_ERR_CNTR_UCC : u8 = 1 << 6; -pub const RST_IRQ_UCC : u8 = 1 << 7; - -pub const CODEGRPSYNCFLG : u16 = 0x470; - -pub const FRAMESYNCFLG : u16 = 0x471; - -pub const GOODCHKSUMFLG : u16 = 0x472; - -pub const INITLANESYNCFLG : u16 = 0x473; - -pub const CTRLREG1 : u16 = 0x476; - -pub const CTRLREG2 : u16 = 0x477; -pub const THRESHOLD_MASK_EN : u8 = 1 << 3; -pub const ILAS_MODE : u8 = 1 << 7; - -pub const KVAL : u16 = 0x478; - -pub const IRQVECTOR_MASK : u16 = 0x47a; -pub const CODEGRPSYNC_MASK : u8 = 1 << 0; -pub const BADCHECKSUM_MASK : u8 = 1 << 2; -pub const INITIALLANESYNC_MASK : u8 = 1 << 3; -pub const UCC_MASK : u8 = 1 << 5; -pub const NIT_MASK : u8 = 1 << 6; -pub const BADDIS_MASK : u8 = 1 << 7; - -pub const SYNCASSERTIONMASK : u16 = 0x47b; -pub const CMM_ENABLE : u8 = 1 << 3; -pub const CMM : u8 = 1 << 4; -pub const UCC_S : u8 = 1 << 5; -pub const NIT_S : u8 = 1 << 6; -pub const BADDIS_S : u8 = 1 << 7; - -pub const ERRORTHRES : u16 = 0x47c; - -pub const LANEENABLE : u16 = 0x47d; - -pub const RAMP_ENA : u16 = 0x47e; - -pub const DIG_TEST0 : u16 = 0x520; -pub const DC_TEST_MODE : u8 = 1 << 1; - -pub const DC_TEST_VALUEI0 : u16 = 0x521; - -pub const DC_TEST_VALUEI1 : u16 = 0x522; - -pub const DC_TEST_VALUEQ0 : u16 = 0x523; - -pub const DC_TEST_VALUEQ1 : u16 = 0x524; diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs deleted file mode 100644 index adf753141..000000000 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ /dev/null @@ -1,419 +0,0 @@ -mod hmc830 { - use board_misoc::{csr, clock}; - - fn spi_setup() { - unsafe { - while csr::converter_spi::idle_read() == 0 {} - csr::converter_spi::offline_write(0); - csr::converter_spi::end_write(1); - csr::converter_spi::cs_polarity_write(0b0001); - csr::converter_spi::clk_polarity_write(0); - csr::converter_spi::clk_phase_write(0); - csr::converter_spi::lsb_first_write(0); - csr::converter_spi::half_duplex_write(0); - csr::converter_spi::length_write(32 - 1); - csr::converter_spi::div_write(16 - 2); - csr::converter_spi::cs_write(1 << csr::CONFIG_CONVERTER_SPI_HMC830_CS); - } - } - - pub fn select_spi_mode() { - spi_setup(); - unsafe { - // rising egde on CS since cs_polarity still 0 - // selects "HMC Mode" - // do a dummy cycle with cs still high to clear CS - csr::converter_spi::length_write(0); - csr::converter_spi::data_write(0); - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::length_write(32 - 1); - } - } - - fn write(addr: u8, data: u32) { - let val = ((addr as u32) << 24) | data; - unsafe { - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::data_write(val << 1); // last clk cycle loads data - } - } - - fn read(addr: u8) -> u32 { - // SDO (miso/read bits) is technically CPHA=1, while SDI is CPHA=0 - // trust that the 8.2ns+0.2ns/pF provide enough hold time on top of - // the SPI round trip delay and stick with CPHA=0 - write((1 << 6) | addr, 0); - unsafe { - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::data_read() & 0xffffff - } - } - - pub fn detect() -> Result<(), &'static str> { - spi_setup(); - let id = read(0x00); - if id != 0xa7975 { - error!("invalid HMC830 ID: 0x{:08x}", id); - return Err("invalid HMC830 identification"); - } - - Ok(()) - } - - pub fn init() { - // Configure HMC830 for integer-N operation - // See "PLLs with integrated VCO- RF Applications Product & Operating - // Guide" - spi_setup(); - info!("loading HMC830 configuration..."); - - write(0x0, 0x20); // software reset - write(0x0, 0x00); // normal operation - write(0x6, 0x307ca); // integer-N mode (NB data sheet table 5.8 not self-consistent) - write(0x7, 0x4d); // digital lock detect, 1/2 cycle window (6.5ns window) - write(0x9, 0x2850); // charge pump: 1.6mA, no offset - write(0xa, 0x2045); // for wideband devices like the HMC830 - write(0xb, 0x7c061); // for HMC830 - - // VCO subsystem registers - // NB software reset does not seem to reset these registers, so always - // program them all! - write(0x5, 0xf88); // 1: defaults - write(0x5, 0x6010); // 2: mute output until output divider set - write(0x5, 0x2818); // 3: wideband PLL defaults - write(0x5, 0x60a0); // 4: HMC830 magic value - write(0x5, 0x1628); // 5: HMC830 magic value - write(0x5, 0x7fb0); // 6: HMC830 magic value - write(0x5, 0x0); // ready for VCO auto-cal - - info!(" ...done"); - } - - pub fn set_dividers(r_div: u32, n_div: u32, m_div: u32, out_div: u32) { - // VCO frequency: f_vco = (f_ref/r_div)*(n_int + n_frac/2**24) - // VCO frequency range [1.5GHz, 3GHz] - // Output frequency: f_out = f_vco/out_div - // Max PFD frequency: 125MHz for integer-N, 100MHz for fractional - // (mode B) - // Max reference frequency: 350MHz, however f_ref >= 200MHz requires - // setting 0x08[21]=1 - // - // Warning: Output divider is not synchronized! Set to 1 for deterministic - // phase at the output. - // - // :param r_div: reference divider [1, 16383] - // :param n_div: VCO divider, integer part. Integer-N mode: [16, 2**19-1] - // fractional mode: [20, 2**19-4] - // :param m_div: VCO divider, fractional part [0, 2**24-1] - // :param out_div: output divider [1, 62] (0 mutes output) - info!("setting HMC830 dividers..."); - write(0x5, 0x6010 + (out_div << 7) + (((out_div <= 2) as u32) << 15)); - write(0x5, 0x0); // ready for VCO auto-cal - write(0x2, r_div); - write(0x4, m_div); - write(0x3, n_div); - - info!(" ...done"); - } - - pub fn check_locked() -> Result<(), &'static str> { - info!("waiting for HMC830 lock..."); - let t = clock::get_ms(); - while read(0x12) & 0x02 == 0 { - if clock::get_ms() > t + 2000 { - error!("lock timeout. Register dump:"); - for addr in 0x00..0x14 { - // These registers don't exist (in the data sheet at least) - if addr == 0x0d || addr == 0x0e { continue; } - error!(" [0x{:02x}] = 0x{:04x}", addr, read(addr)); - } - return Err("lock timeout"); - } - } - info!(" ...locked"); - - Ok(()) - } -} - -pub mod hmc7043 { - use board_misoc::{csr, clock}; - - // Warning: dividers are not synchronized with HMC830 clock input! - // Set DAC_CLK_DIV to 1 or 0 for deterministic phase. - // (0 bypasses the divider and reduces noise) - const DAC_CLK_DIV: u16 = 0; - const FPGA_CLK_DIV: u16 = 16; // Keep in sync with jdcg.rs - const SYSREF_DIV: u16 = 256; // Keep in sync with jdcg.rs - const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // must be <= 4MHz - - // enabled, divider, output config, is sysref - const OUTPUT_CONFIG: [(bool, u16, u8, bool); 14] = [ - (true, DAC_CLK_DIV, 0x08, false), // 0: DAC1_CLK - (true, SYSREF_DIV, 0x01, true), // 1: DAC1_SYSREF - (true, DAC_CLK_DIV, 0x08, false), // 2: DAC0_CLK - (true, SYSREF_DIV, 0x01, true), // 3: DAC0_SYSREF - (true, SYSREF_DIV, 0x10, true), // 4: AMC_FPGA_SYSREF0 - (false, FPGA_CLK_DIV, 0x10, true), // 5: AMC_FPGA_SYSREF1 - (false, 0, 0x10, false), // 6: unused - (true, FPGA_CLK_DIV, 0x10, true), // 7: RTM_FPGA_SYSREF0 - (true, FPGA_CLK_DIV, 0x08, false), // 8: GTP_CLK0_IN - (false, 0, 0x10, false), // 9: unused - (false, 0, 0x10, false), // 10: unused - (false, 0, 0x08, false), // 11: unused / uFL - (false, 0, 0x10, false), // 12: unused - (false, FPGA_CLK_DIV, 0x10, true), // 13: RTM_FPGA_SYSREF1 - ]; - - fn spi_setup() { - unsafe { - while csr::converter_spi::idle_read() == 0 {} - csr::converter_spi::offline_write(0); - csr::converter_spi::end_write(1); - csr::converter_spi::cs_polarity_write(0b0001); - csr::converter_spi::clk_polarity_write(0); - csr::converter_spi::clk_phase_write(0); - csr::converter_spi::lsb_first_write(0); - csr::converter_spi::half_duplex_write(0); // change mid-transaction for reads - csr::converter_spi::length_write(24 - 1); - csr::converter_spi::div_write(16 - 2); - csr::converter_spi::cs_write(1 << csr::CONFIG_CONVERTER_SPI_HMC7043_CS); - } - } - - fn spi_wait_idle() { - unsafe { - while csr::converter_spi::idle_read() == 0 {} - } - } - - fn write(addr: u16, data: u8) { - let cmd = (0 << 15) | addr; - let val = ((cmd as u32) << 8) | data as u32; - unsafe { - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::data_write(val << 8); - } - } - - fn read(addr: u16) -> u8 { - let cmd = (1 << 15) | addr; - let val = cmd as u32; - unsafe { - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::end_write(0); - csr::converter_spi::length_write(16 - 1); - csr::converter_spi::data_write(val << 16); - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::end_write(1); - csr::converter_spi::half_duplex_write(1); - csr::converter_spi::length_write(8 - 1); - csr::converter_spi::data_write(0); - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::half_duplex_write(0); - csr::converter_spi::length_write(24 - 1); - csr::converter_spi::data_read() as u8 - } - } - - pub const CHIP_ID: u32 = 0xf17904; - - pub fn get_id() -> u32 { - spi_setup(); - (read(0x78) as u32) << 16 | (read(0x79) as u32) << 8 | read(0x7a) as u32 - } - - pub fn detect() -> Result<(), &'static str> { - let id = get_id(); - if id != CHIP_ID { - error!("invalid HMC7043 ID: 0x{:08x}", id); - return Err("invalid HMC7043 identification"); - } - - Ok(()) - } - - pub fn enable() { - info!("enabling HMC7043"); - - unsafe { - csr::hmc7043_reset::out_write(0); - } - clock::spin_us(10_000); - - spi_setup(); - write(0x0, 0x1); // Software reset - write(0x0, 0x0); // Normal operation - write(0x1, 0x48); // mute all outputs - } - - const GPO_MUX_CLK_OUT_PHASE: u8 = 3; - const GPO_MUX_FORCE1: u8 = 10; - const GPO_MUX_FORCE0: u8 = 11; - - /* Read an HMC7043 internal status bit through the GPO interface. - * This method is required to work around bugs in the register interface. - */ - fn gpo_indirect_read(mux_setting: u8) -> bool { - write(0x50, (mux_setting << 2) | 0x3); - spi_wait_idle(); - unsafe { - csr::hmc7043_gpo::in_read() == 1 - } - } - - pub fn init() { - spi_setup(); - info!("loading configuration..."); - - write(0x3, 0x14); // Disable the RFSYNCIN reseeder - write(0xA, 0x06); // Disable the RFSYNCIN input buffer - write(0xB, 0x07); // Enable the CLKIN input as LVPECL - write(0x9F, 0x4d); // Unexplained high-performance mode - write(0xA0, 0xdf); // Unexplained high-performance mode - - // Enable required output groups - let mut output_group_en = 0; - for channel in 0..OUTPUT_CONFIG.len() { - let enabled = OUTPUT_CONFIG[channel].0; - if enabled { - let group = channel/2; - output_group_en |= 1 << group; - } - } - write(0x4, output_group_en); - - // Set SYSREF timer divider. - // We don't need this "feature", but the HMC7043 won't work without. - write(0x5c, (HMC_SYSREF_DIV & 0xff) as u8); - write(0x5d, ((HMC_SYSREF_DIV & 0xf00) >> 8) as u8); - - for channel in 0..OUTPUT_CONFIG.len() { - let channel_base = 0xc8 + 0x0a*(channel as u16); - let (enabled, divider, outcfg, is_sysref) = OUTPUT_CONFIG[channel]; - - if enabled { - if !is_sysref { - // DCLK channel: enable high-performance mode - write(channel_base, 0xd1); - } else { - // SYSREF channel: disable hi-perf mode, enable slip - write(channel_base, 0x71); - } - } else { - write(channel_base, 0x10); - } - write(channel_base + 0x1, (divider & 0xff) as u8); - write(channel_base + 0x2, ((divider & 0xf00) >> 8) as u8); - - // bypass analog phase shift on DCLK channels to reduce noise - if !is_sysref { - if divider != 0 { - write(channel_base + 0x7, 0x00); // enable divider - } else { - write(channel_base + 0x7, 0x03); // bypass divider for lowest noise - } - } else { - write(channel_base + 0x7, 0x01); - } - - write(channel_base + 0x8, outcfg) - } - - write(0x1, 0x4a); // Reset dividers and FSMs - write(0x1, 0x48); - write(0x1, 0xc8); // Synchronize dividers - write(0x1, 0x40); // Unmute, high-performance/low-noise mode - - clock::spin_us(10_000); - - info!(" ...done"); - } - - pub fn test_gpo() -> Result<(), &'static str> { - info!("testing GPO..."); - for trial in 0..10 { - if !gpo_indirect_read(GPO_MUX_FORCE1) { - info!(" ...failed. GPO I/O did not go high (#{})", trial + 1); - return Err("GPO is not functioning"); - } - if gpo_indirect_read(GPO_MUX_FORCE0) { - info!(" ...failed. GPO I/O did not return low (#{})", trial + 1); - return Err("GPO is not functioning"); - } - } - info!(" ...passed"); - Ok(()) - } - - pub fn check_phased() -> Result<(), &'static str> { - if !gpo_indirect_read(GPO_MUX_CLK_OUT_PHASE) { - return Err("GPO reported phases did not align"); - } - // Should be the same as the GPO read - let sysref_fsm_status = read(0x91); - if sysref_fsm_status != 0x2 { - error!("Bad SYSREF FSM status: {:02x}", sysref_fsm_status); - return Err("Bad SYSREF FSM status"); - } - Ok(()) - } - - pub fn unmute() { - /* - * Never missing an opportunity to be awful, the HMC7043 produces broadband noise - * prior to intialization, which can upset the AMC FPGA. - * External circuitry mutes it. - */ - unsafe { - csr::hmc7043_out_en::out_write(1); - } - } - - pub fn sysref_delay_dac(dacno: u8, phase_offset: u8) { - spi_setup(); - if dacno == 0 { - write(0x00e9, phase_offset); - } else if dacno == 1 { - write(0x00d5, phase_offset); - } else { - unimplemented!(); - } - clock::spin_us(100); - } - - pub fn sysref_slip() { - spi_setup(); - write(0x0002, 0x02); - write(0x0002, 0x00); - clock::spin_us(100); - } -} - -pub fn init() -> Result<(), &'static str> { - #[cfg(all(hmc830_ref = "125", rtio_frequency = "125.0"))] - const DIV: (u32, u32, u32, u32) = (2, 32, 0, 1); // 125MHz -> 2.0GHz - #[cfg(all(hmc830_ref = "150", rtio_frequency = "150.0"))] - const DIV: (u32, u32, u32, u32) = (2, 32, 0, 1); // 150MHz -> 2.4GHz - - /* do not use other SPI devices before HMC830 SPI mode selection */ - hmc830::select_spi_mode(); - hmc830::detect()?; - hmc830::init(); - - hmc830::set_dividers(DIV.0, DIV.1, DIV.2, DIV.3); - - hmc830::check_locked()?; - - if hmc7043::get_id() == hmc7043::CHIP_ID { - error!("HMC7043 detected while in reset (board rework missing?)"); - } - hmc7043::enable(); - hmc7043::detect()?; - hmc7043::init(); - hmc7043::test_gpo()?; - hmc7043::check_phased()?; - hmc7043::unmute(); - - Ok(()) -} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 694805cfa..7436fc8c5 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -25,13 +25,6 @@ pub mod si5324; #[cfg(has_wrpll)] pub mod wrpll; -#[cfg(has_hmc830_7043)] -pub mod hmc830_7043; -#[cfg(has_ad9154)] -mod ad9154_reg; -#[cfg(has_ad9154)] -pub mod ad9154; - #[cfg(has_grabber)] pub mod grabber; diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index f5e816f14..249581932 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -182,12 +182,6 @@ fn init() -> Result<()> { i2c::pca9548_select(BUSNO, 0x70, 0)?; i2c::pca9548_select(BUSNO, 0x71, 1 << 3)?; } - #[cfg(soc_platform = "sayma_amc")] - i2c::pca9548_select(BUSNO, 0x70, 1 << 4)?; - #[cfg(soc_platform = "sayma_rtm")] - i2c::pca9548_select(BUSNO, 0x77, 1 << 5)?; - #[cfg(soc_platform = "metlino")] - i2c::pca9548_select(BUSNO, 0x70, 1 << 4)?; #[cfg(soc_platform = "kc705")] i2c::pca9548_select(BUSNO, 0x74, 1 << 7)?; diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 4b0fa9754..a9c9a702f 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -175,8 +175,6 @@ mod si549 { use board_misoc::clock; use super::i2c; - #[cfg(any(soc_platform = "metlino", soc_platform = "sayma_amc", soc_platform = "sayma_rtm"))] - pub const ADDRESS: u8 = 0x55; #[cfg(soc_platform = "kasli")] pub const ADDRESS: u8 = 0x67; diff --git a/artiq/firmware/libboard_misoc/net_settings.rs b/artiq/firmware/libboard_misoc/net_settings.rs index 2663be5db..2f02cb157 100644 --- a/artiq/firmware/libboard_misoc/net_settings.rs +++ b/artiq/firmware/libboard_misoc/net_settings.rs @@ -39,10 +39,6 @@ pub fn get_adresses() -> NetAddresses { .map(|addr_buf| EthernetAddress(addr_buf)) .unwrap_or_else(|_e| EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x21])); } - #[cfg(soc_platform = "sayma_amc")] - { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x11]); } - #[cfg(soc_platform = "metlino")] - { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x19]); } #[cfg(soc_platform = "kc705")] { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); } } @@ -54,10 +50,6 @@ pub fn get_adresses() -> NetAddresses { _ => { #[cfg(soc_platform = "kasli")] { ipv4_addr = IpAddress::v4(192, 168, 1, 70); } - #[cfg(soc_platform = "sayma_amc")] - { ipv4_addr = IpAddress::v4(192, 168, 1, 60); } - #[cfg(soc_platform = "metlino")] - { ipv4_addr = IpAddress::v4(192, 168, 1, 65); } #[cfg(soc_platform = "kc705")] { ipv4_addr = IpAddress::v4(192, 168, 1, 50); } } diff --git a/artiq/firmware/libboard_misoc/spiflash.rs b/artiq/firmware/libboard_misoc/spiflash.rs index 9b5ca31f5..598d96633 100644 --- a/artiq/firmware/libboard_misoc/spiflash.rs +++ b/artiq/firmware/libboard_misoc/spiflash.rs @@ -114,7 +114,7 @@ pub unsafe fn write(mut addr: usize, mut data: &[u8]) { } } -#[cfg(any(soc_platform = "kasli", soc_platform = "metlino", soc_platform = "kc705"))] +#[cfg(any(soc_platform = "kasli", soc_platform = "kc705"))] pub unsafe fn reload () -> ! { csr::icap::iprog_write(1); loop {} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 45fb76f91..2846b02f2 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -364,7 +364,7 @@ pub fn panic_impl(info: &core::panic::PanicInfo) -> ! { }); if config::read_str("panic_reset", |r| r == Ok("1")) && - cfg!(any(soc_platform = "kasli", soc_platform = "metlino", soc_platform = "kc705")) { + cfg!(any(soc_platform = "kasli", soc_platform = "kc705")) { println!("restarting..."); unsafe { kernel::stop(); diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index f0330b4d9..f5159ad2f 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -172,7 +172,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { crystal_ref: true } }, - RtioClock::Int_100 => { // 100MHz output, from crystal. Also used as reference for Sayma HMC830. + RtioClock::Int_100 => { // 100MHz output, from crystal info!("using internal 100MHz RTIO clock"); si5324::FrequencySettings { n1_hs : 9, @@ -218,8 +218,6 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { let si5324_ref_input = si5324::Input::Ckin1; #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] let si5324_ref_input = si5324::Input::Ckin2; - #[cfg(soc_platform = "metlino")] - let si5324_ref_input = si5324::Input::Ckin2; #[cfg(soc_platform = "kc705")] let si5324_ref_input = si5324::Input::Ckin2; si5324::setup(&si5324_settings, si5324_ref_input).expect("cannot initialize Si5324"); @@ -233,8 +231,6 @@ pub fn init() { let si5324_ext_input = si5324::Input::Ckin1; #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] let si5324_ext_input = si5324::Input::Ckin2; - #[cfg(soc_platform = "metlino")] - let si5324_ext_input = si5324::Input::Ckin2; #[cfg(soc_platform = "kc705")] let si5324_ext_input = si5324::Input::Ckin2; match clock_cfg { diff --git a/artiq/firmware/satman/jdac_common.rs b/artiq/firmware/satman/jdac_common.rs deleted file mode 100644 index 3c185516f..000000000 --- a/artiq/firmware/satman/jdac_common.rs +++ /dev/null @@ -1,74 +0,0 @@ -pub const INIT: u8 = 0x00; -pub const PRINT_STATUS: u8 = 0x01; -pub const PRBS: u8 = 0x02; -pub const STPL: u8 = 0x03; - -pub const SYSREF_DELAY_DAC: u8 = 0x10; -pub const SYSREF_SLIP: u8 = 0x11; -pub const SYNC: u8 = 0x12; - -pub const DDMTD_SYSREF_RAW: u8 = 0x20; -pub const DDMTD_SYSREF: u8 = 0x21; - - -fn average_2phases(a: i32, b: i32, modulo: i32) -> i32 { - let diff = ((a - b + modulo/2 + modulo) % modulo) - modulo/2; - return (modulo + b + diff/2) % modulo; -} - -pub fn average_phases(phases: &[i32], modulo: i32) -> i32 { - if phases.len() == 1 { - panic!("input array length must be a power of 2"); - } else if phases.len() == 2 { - average_2phases(phases[0], phases[1], modulo) - } else { - let cut = phases.len()/2; - average_2phases( - average_phases(&phases[..cut], modulo), - average_phases(&phases[cut..], modulo), - modulo) - } -} - -pub const RAW_DDMTD_N_SHIFT: i32 = 6; -pub const RAW_DDMTD_N: i32 = 1 << RAW_DDMTD_N_SHIFT; -pub const DDMTD_DITHER_BITS: i32 = 1; -pub const DDMTD_N_SHIFT: i32 = RAW_DDMTD_N_SHIFT + DDMTD_DITHER_BITS; -pub const DDMTD_N: i32 = 1 << DDMTD_N_SHIFT; - -#[cfg(has_ad9154)] -use board_misoc::{clock, csr}; - -#[cfg(has_ad9154)] -pub fn init_ddmtd() -> Result<(), &'static str> { - unsafe { - csr::sysref_ddmtd::reset_write(1); - clock::spin_us(1); - csr::sysref_ddmtd::reset_write(0); - clock::spin_us(100); - if csr::sysref_ddmtd::locked_read() != 0 { - Ok(()) - } else { - Err("DDMTD helper PLL failed to lock") - } - } -} - -#[cfg(has_ad9154)] -pub fn measure_ddmdt_phase_raw() -> i32 { - unsafe { csr::sysref_ddmtd::dt_read() as i32 } -} - -#[cfg(has_ad9154)] -pub fn measure_ddmdt_phase() -> i32 { - const AVG_PRECISION_SHIFT: i32 = 6; - const AVG_PRECISION: i32 = 1 << AVG_PRECISION_SHIFT; - const AVG_MOD: i32 = 1 << (RAW_DDMTD_N_SHIFT + AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); - - let mut measurements = [0; AVG_PRECISION as usize]; - for i in 0..AVG_PRECISION { - measurements[i as usize] = measure_ddmdt_phase_raw() << (AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); - clock::spin_us(10); - } - average_phases(&measurements, AVG_MOD) >> AVG_PRECISION_SHIFT -} diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs deleted file mode 100644 index c8a34827b..000000000 --- a/artiq/firmware/satman/jdcg.rs +++ /dev/null @@ -1,589 +0,0 @@ -pub mod jesd { - use board_misoc::{csr, clock}; - - pub fn reset(reset: bool) { - unsafe { - csr::jesd_crg::jreset_write(if reset {1} else {0}); - } - } - - pub fn enable(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_enable_write)(if en {1} else {0}) - } - } - - pub fn phy_done(dacno: u8) -> bool { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_phy_done_read)() != 0 - } - } - - pub fn ready(dacno: u8) -> bool { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_ready_read)() != 0 - } - } - - pub fn prbs(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00}) - } - clock::spin_us(5000); - } - - pub fn stpl(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_stpl_enable_write)(if en {1} else {0}) - } - clock::spin_us(5000); - } - - pub fn jsync(dacno: u8) -> bool { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_jsync_read)() != 0 - } - } -} - -pub mod jdac { - use board_misoc::{csr, clock}; - use board_artiq::drtioaux; - - use super::jesd; - use super::super::jdac_common; - - pub fn basic_request(dacno: u8, reqno: u8, param: u8) -> Result { - if let Err(e) = drtioaux::send(1, &drtioaux::Packet::JdacBasicRequest { - destination: 0, - dacno: dacno, - reqno: reqno, - param: param - }) { - error!("aux packet error ({})", e); - return Err("aux packet error while sending for JESD DAC basic request"); - } - match drtioaux::recv_timeout(1, Some(1000)) { - Ok(drtioaux::Packet::JdacBasicReply { succeeded, retval }) => { - if succeeded { - Ok(retval) - } else { - error!("JESD DAC basic request failed (dacno={}, reqno={})", dacno, reqno); - Err("remote error status to JESD DAC basic request") - } - }, - Ok(packet) => { - error!("received unexpected aux packet: {:?}", packet); - Err("unexpected aux packet in reply to JESD DAC basic request") - }, - Err(e) => { - error!("aux packet error ({})", e); - Err("aux packet error while waiting for JESD DAC basic reply") - } - } - } - - pub fn init() -> Result<(), &'static str> { - for dacno in 0..csr::JDCG.len() { - let dacno = dacno as u8; - info!("DAC-{} initializing...", dacno); - - jesd::enable(dacno, true); - clock::spin_us(10_000); - if !jesd::phy_done(dacno) { - error!("JESD core PHY not done"); - return Err("JESD core PHY not done"); - } - - basic_request(dacno, jdac_common::INIT, 0)?; - - // JESD ready depends on JSYNC being valid, so DAC init needs to happen first - if !jesd::ready(dacno) { - error!("JESD core reported not ready, sending DAC status print request"); - basic_request(dacno, jdac_common::PRINT_STATUS, 0)?; - return Err("JESD core reported not ready"); - } - - jesd::prbs(dacno, true); - basic_request(dacno, jdac_common::PRBS, 0)?; - jesd::prbs(dacno, false); - - basic_request(dacno, jdac_common::INIT, 0)?; - clock::spin_us(5000); - - if !jesd::jsync(dacno) { - error!("JESD core reported bad SYNC"); - return Err("JESD core reported bad SYNC"); - } - - info!(" ...done initializing"); - } - Ok(()) - } - - pub fn stpl() -> Result<(), &'static str> { - for dacno in 0..csr::JDCG.len() { - let dacno = dacno as u8; - - info!("Running STPL test on DAC-{}...", dacno); - - jesd::stpl(dacno, true); - basic_request(dacno, jdac_common::STPL, 0)?; - jesd::stpl(dacno, false); - - info!(" ...done STPL test"); - } - Ok(()) - } -} - -pub mod jesd204sync { - use board_misoc::{csr, clock, config}; - - use super::jdac; - use super::super::jdac_common; - - const HMC7043_ANALOG_DELAY_RANGE: u8 = 24; - - const FPGA_CLK_DIV: u16 = 16; // Keep in sync with hmc830_7043.rs - const SYSREF_DIV: u16 = 256; // Keep in sync with hmc830_7043.rs - - fn hmc7043_sysref_delay_dac(dacno: u8, phase_offset: u8) -> Result<(), &'static str> { - match jdac::basic_request(dacno, jdac_common::SYSREF_DELAY_DAC, phase_offset) { - Ok(_) => Ok(()), - Err(e) => Err(e) - } - } - - - fn hmc7043_sysref_slip() -> Result<(), &'static str> { - match jdac::basic_request(0, jdac_common::SYSREF_SLIP, 0) { - Ok(_) => Ok(()), - Err(e) => Err(e) - } - } - - fn ad9154_sync(dacno: u8) -> Result { - match jdac::basic_request(dacno, jdac_common::SYNC, 0) { - Ok(0) => Ok(false), - Ok(_) => Ok(true), - Err(e) => Err(e) - } - } - - fn measure_ddmdt_phase_raw() -> Result { - Ok(jdac::basic_request(0, jdac_common::DDMTD_SYSREF_RAW, 0)? as i32) - } - - fn measure_ddmdt_phase() -> Result { - Ok(jdac::basic_request(0, jdac_common::DDMTD_SYSREF, 0)? as i32) - } - - fn test_ddmtd_stability(raw: bool, tolerance: i32) -> Result<(), &'static str> { - info!("testing DDMTD stability (raw={}, tolerance={})...", raw, tolerance); - - let modulo = if raw { jdac_common::RAW_DDMTD_N } else { jdac_common::DDMTD_N }; - let measurement = if raw { measure_ddmdt_phase_raw } else { measure_ddmdt_phase }; - let ntests = if raw { 150 } else { 15 }; - - let mut max_pkpk = 0; - for _ in 0..32 { - // If we are near the edges, wraparound can throw off the simple min/max computation. - // In this case, add an offset to get near the center. - let quadrant = measure_ddmdt_phase()?; - let center_offset = - if quadrant < jdac_common::DDMTD_N/4 || quadrant > 3*jdac_common::DDMTD_N/4 { - modulo/2 - } else { - 0 - }; - - let mut min = modulo; - let mut max = 0; - for _ in 0..ntests { - let m = (measurement()? + center_offset) % modulo; - if m < min { - min = m; - } - if m > max { - max = m; - } - } - let pkpk = max - min; - if pkpk > max_pkpk { - max_pkpk = pkpk; - } - if pkpk > tolerance { - error!(" ...excessive peak-peak jitter: {} (min={} max={} center_offset={})", pkpk, - min, max, center_offset); - return Err("excessive DDMTD peak-peak jitter"); - } - hmc7043_sysref_slip(); - } - - info!(" ...passed, peak-peak jitter: {}", max_pkpk); - Ok(()) - } - - fn test_slip_ddmtd() -> Result<(), &'static str> { - // expected_step = (RTIO clock frequency)*(DDMTD N)/(HMC7043 CLKIN frequency) - let expected_step = 8; - let tolerance = 1; - - info!("testing HMC7043 SYSREF slip against DDMTD..."); - let mut old_phase = measure_ddmdt_phase()?; - for _ in 0..1024 { - hmc7043_sysref_slip(); - let phase = measure_ddmdt_phase()?; - let step = (jdac_common::DDMTD_N + old_phase - phase) % jdac_common::DDMTD_N; - if (step - expected_step).abs() > tolerance { - error!(" ...got unexpected step: {} ({} -> {})", step, old_phase, phase); - return Err("HMC7043 SYSREF slip produced unexpected DDMTD step"); - } - old_phase = phase; - } - info!(" ...passed"); - Ok(()) - } - - fn sysref_sh_error() -> bool { - unsafe { - csr::sysref_sampler::sh_error_reset_write(1); - clock::spin_us(1); - csr::sysref_sampler::sh_error_reset_write(0); - clock::spin_us(10); - csr::sysref_sampler::sh_error_read() != 0 - } - } - - const SYSREF_SH_PRECISION_SHIFT: i32 = 5; - const SYSREF_SH_PRECISION: i32 = 1 << SYSREF_SH_PRECISION_SHIFT; - const SYSREF_SH_MOD: i32 = 1 << (jdac_common::DDMTD_N_SHIFT + SYSREF_SH_PRECISION_SHIFT); - - #[derive(Default)] - struct SysrefShLimits { - rising_phases: [i32; SYSREF_SH_PRECISION as usize], - falling_phases: [i32; SYSREF_SH_PRECISION as usize], - } - - fn measure_sysref_sh_limits() -> Result { - let mut ret = SysrefShLimits::default(); - let mut nslips = 0; - let mut rising_n = 0; - let mut falling_n = 0; - - let mut previous = sysref_sh_error(); - while rising_n < SYSREF_SH_PRECISION || falling_n < SYSREF_SH_PRECISION { - hmc7043_sysref_slip(); - nslips += 1; - if nslips > 1024 { - return Err("too many slips and not enough SYSREF S/H error transitions"); - } - - let current = sysref_sh_error(); - let phase = measure_ddmdt_phase()?; - if current && !previous && rising_n < SYSREF_SH_PRECISION { - ret.rising_phases[rising_n as usize] = phase << SYSREF_SH_PRECISION_SHIFT; - rising_n += 1; - } - if !current && previous && falling_n < SYSREF_SH_PRECISION { - ret.falling_phases[falling_n as usize] = phase << SYSREF_SH_PRECISION_SHIFT; - falling_n += 1; - } - previous = current; - } - Ok(ret) - } - - fn max_phase_deviation(average: i32, phases: &[i32]) -> i32 { - let mut ret = 0; - for phase in phases.iter() { - let deviation = (phase - average + jdac_common::DDMTD_N) % jdac_common::DDMTD_N; - if deviation > ret { - ret = deviation; - } - } - return ret; - } - - fn reach_sysref_ddmtd_target(target: i32, tolerance: i32) -> Result { - for _ in 0..1024 { - let delta = (measure_ddmdt_phase()? - target + jdac_common::DDMTD_N) % jdac_common::DDMTD_N; - if delta <= tolerance { - return Ok(delta) - } - hmc7043_sysref_slip(); - } - Err("failed to reach SYSREF DDMTD phase target") - } - - fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result { - info!("calibrating SYSREF DDMTD target phase..."); - let coarse_target = - if rising_average < falling_average { - (rising_average + falling_average)/2 - } else { - ((falling_average - (jdac_common::DDMTD_N - rising_average))/2 + jdac_common::DDMTD_N) % jdac_common::DDMTD_N - }; - info!(" SYSREF calibration coarse target: {}", coarse_target); - reach_sysref_ddmtd_target(coarse_target, 8)?; - let target = measure_ddmdt_phase()?; - info!(" ...done, target={}", target); - Ok(target) - } - - fn sysref_get_tsc_phase_raw() -> Result { - if sysref_sh_error() { - return Err("SYSREF failed S/H timing"); - } - let ret = unsafe { csr::sysref_sampler::sysref_phase_read() }; - Ok(ret) - } - - // Note: the code below assumes RTIO/SYSREF frequency ratio is a power of 2 - - fn sysref_get_tsc_phase() -> Result { - let mask = (SYSREF_DIV/FPGA_CLK_DIV - 1) as u8; - Ok((sysref_get_tsc_phase_raw()? & mask) as i32) - } - - pub fn test_sysref_frequency() -> Result<(), &'static str> { - info!("testing SYSREF frequency against raw TSC phase bit toggles..."); - - let mut all_toggles = 0; - let initial_phase = sysref_get_tsc_phase_raw()?; - for _ in 0..20000 { - clock::spin_us(1); - all_toggles |= sysref_get_tsc_phase_raw()? ^ initial_phase; - } - - let ratio = (SYSREF_DIV/FPGA_CLK_DIV) as u8; - let expected_toggles = 0xff ^ (ratio - 1); - if all_toggles == expected_toggles { - info!(" ...done (0x{:02x})", all_toggles); - Ok(()) - } else { - error!(" ...unexpected toggles: got 0x{:02x}, expected 0x{:02x}", - all_toggles, expected_toggles); - Err("unexpected toggles") - } - } - - fn sysref_slip_rtio_cycle() { - for _ in 0..FPGA_CLK_DIV { - hmc7043_sysref_slip(); - } - } - - pub fn test_slip_tsc() -> Result<(), &'static str> { - info!("testing HMC7043 SYSREF slip against TSC phase..."); - let initial_phase = sysref_get_tsc_phase()?; - let modulo = (SYSREF_DIV/FPGA_CLK_DIV) as i32; - for i in 0..128 { - sysref_slip_rtio_cycle(); - let expected_phase = (initial_phase + i + 1) % modulo; - let phase = sysref_get_tsc_phase()?; - if phase != expected_phase { - error!(" ...unexpected TSC phase: got {}, expected {} ", phase, expected_phase); - return Err("HMC7043 SYSREF slip produced unexpected TSC phase"); - } - } - info!(" ...done"); - Ok(()) - } - - pub fn sysref_rtio_align() -> Result<(), &'static str> { - info!("aligning SYSREF with RTIO TSC..."); - let mut nslips = 0; - loop { - sysref_slip_rtio_cycle(); - if sysref_get_tsc_phase()? == 0 { - info!(" ...done"); - return Ok(()) - } - - nslips += 1; - if nslips > SYSREF_DIV/FPGA_CLK_DIV { - return Err("failed to find SYSREF transition aligned with RTIO TSC"); - } - } - } - - pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { - test_ddmtd_stability(true, 4)?; - test_ddmtd_stability(false, 1)?; - test_slip_ddmtd()?; - - info!("determining SYSREF S/H limits..."); - let sysref_sh_limits = measure_sysref_sh_limits()?; - let rising_average = jdac_common::average_phases(&sysref_sh_limits.rising_phases, SYSREF_SH_MOD); - let falling_average = jdac_common::average_phases(&sysref_sh_limits.falling_phases, SYSREF_SH_MOD); - let rising_max_deviation = max_phase_deviation(rising_average, &sysref_sh_limits.rising_phases); - let falling_max_deviation = max_phase_deviation(falling_average, &sysref_sh_limits.falling_phases); - - let rising_average = rising_average >> SYSREF_SH_PRECISION_SHIFT; - let falling_average = falling_average >> SYSREF_SH_PRECISION_SHIFT; - let rising_max_deviation = rising_max_deviation >> SYSREF_SH_PRECISION_SHIFT; - let falling_max_deviation = falling_max_deviation >> SYSREF_SH_PRECISION_SHIFT; - - info!(" SYSREF S/H average limits (DDMTD phases): {} {}", rising_average, falling_average); - info!(" SYSREF S/H maximum limit deviation: {} {}", rising_max_deviation, falling_max_deviation); - if rising_max_deviation > 8 || falling_max_deviation > 8 { - return Err("excessive SYSREF S/H limit deviation"); - } - info!(" ...done"); - - let entry = config::read_str("sysref_ddmtd_phase_fpga", |r| r.map(|s| s.parse())); - let target_phase = match entry { - Ok(Ok(phase)) => { - info!("using FPGA SYSREF DDMTD phase target from config: {}", phase); - phase - } - _ => { - let phase = calibrate_sysref_target(rising_average, falling_average)?; - if let Err(e) = config::write_int("sysref_ddmtd_phase_fpga", phase as u32) { - error!("failed to update FPGA SYSREF DDMTD phase target in config: {}", e); - } - phase - } - }; - - info!("aligning SYSREF with RTIO clock..."); - let delta = reach_sysref_ddmtd_target(target_phase, 3)?; - if sysref_sh_error() { - return Err("SYSREF does not meet S/H timing at DDMTD phase target"); - } - info!(" ...done, delta={}", delta); - - test_sysref_frequency()?; - test_slip_tsc()?; - sysref_rtio_align()?; - - Ok(()) - } - - fn sysref_cal_dac(dacno: u8) -> Result { - info!("calibrating SYSREF delay at DAC-{}...", dacno); - - // Allocate for more than expected as jitter may create spurious entries. - let mut limits_buf = [0; 8]; - let mut n_limits = 0; - - limits_buf[n_limits] = -1; - n_limits += 1; - - // avoid spurious rotation at delay=0 - hmc7043_sysref_delay_dac(dacno, 0); - ad9154_sync(dacno)?; - - for scan_delay in 0..HMC7043_ANALOG_DELAY_RANGE { - hmc7043_sysref_delay_dac(dacno, scan_delay); - if ad9154_sync(dacno)? { - limits_buf[n_limits] = scan_delay as i16; - n_limits += 1; - if n_limits >= limits_buf.len() - 1 { - break; - } - } - } - - limits_buf[n_limits] = HMC7043_ANALOG_DELAY_RANGE as i16; - n_limits += 1; - - info!(" using limits: {:?}", &limits_buf[..n_limits]); - - let mut delay = 0; - let mut best_margin = 0; - - for i in 0..(n_limits-1) { - let margin = limits_buf[i+1] - limits_buf[i]; - if margin > best_margin { - best_margin = margin; - delay = ((limits_buf[i+1] + limits_buf[i])/2) as u8; - } - } - - info!(" ...done, delay={}", delay); - Ok(delay) - } - - fn sysref_dac_align(dacno: u8, delay: u8) -> Result<(), &'static str> { - let tolerance = 5; - - info!("verifying SYSREF margins at DAC-{}...", dacno); - - // avoid spurious rotation at delay=0 - hmc7043_sysref_delay_dac(dacno, 0); - ad9154_sync(dacno)?; - - let mut rotation_seen = false; - for scan_delay in 0..HMC7043_ANALOG_DELAY_RANGE { - hmc7043_sysref_delay_dac(dacno, scan_delay); - if ad9154_sync(dacno)? { - rotation_seen = true; - let distance = (scan_delay as i16 - delay as i16).abs(); - if distance < tolerance { - error!(" rotation at delay={} is {} delay steps from target (FAIL)", scan_delay, distance); - return Err("insufficient SYSREF margin at DAC"); - } else { - info!(" rotation at delay={} is {} delay steps from target (PASS)", scan_delay, distance); - } - } - } - - if !rotation_seen { - return Err("no rotation seen when scanning DAC SYSREF delay"); - } - - info!(" ...done"); - - // We tested that the value is correct - now use it - info!("synchronizing DAC-{}", dacno); - hmc7043_sysref_delay_dac(dacno, delay); - ad9154_sync(dacno)?; - - Ok(()) - } - - pub fn sysref_auto_dac_align() -> Result<(), &'static str> { - // We assume that DAC SYSREF traces are length-matched so only one delay - // value is needed, and we use DAC-0 as calibration reference. - - let entry = config::read_str("sysref_7043_delay_dac", |r| r.map(|s| s.parse())); - let delay = match entry { - Ok(Ok(delay)) => { - info!("using DAC SYSREF delay from config: {}", delay); - delay - }, - _ => { - let delay = sysref_cal_dac(0)?; - if let Err(e) = config::write_int("sysref_7043_delay_dac", delay as u32) { - error!("failed to update DAC SYSREF delay in config: {}", e); - } - delay - } - }; - - for dacno in 0..csr::JDCG.len() { - sysref_dac_align(dacno as u8, delay)?; - } - Ok(()) - } - - pub fn sysref_auto_align() { - if let Err(e) = sysref_auto_rtio_align() { - error!("failed to align SYSREF at FPGA: {}", e); - } - if let Err(e) = sysref_auto_dac_align() { - error!("failed to align SYSREF at DAC: {}", e); - } - } - - pub fn resync_dacs() -> Result<(), &'static str> { - for dacno in 0..csr::JDCG.len() { - info!("resynchronizing DAC-{}", dacno); - ad9154_sync(dacno as u8)?; - } - Ok(()) - } -} diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index c6685f895..3784eff20 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -16,15 +16,9 @@ use board_artiq::si5324; use board_artiq::wrpll; use board_artiq::{spi, drtioaux}; use board_artiq::drtio_routing; -#[cfg(has_hmc830_7043)] -use board_artiq::hmc830_7043; use riscv::register::{mcause, mepc, mtval}; mod repeater; -#[cfg(has_jdcg)] -mod jdcg; -#[cfg(any(has_ad9154, has_jdcg))] -pub mod jdac_common; fn drtiosat_reset(reset: bool) { unsafe { @@ -298,43 +292,6 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } } - drtioaux::Packet::JdacBasicRequest { destination: _destination, dacno: _dacno, - reqno: _reqno, param: _param } => { - forward!(_routing_table, _destination, *_rank, _repeaters, &packet); - #[cfg(has_ad9154)] - let (succeeded, retval) = { - #[cfg(rtio_frequency = "125.0")] - const LINERATE: u64 = 5_000_000_000; - #[cfg(rtio_frequency = "150.0")] - const LINERATE: u64 = 6_000_000_000; - match _reqno { - jdac_common::INIT => (board_artiq::ad9154::setup(_dacno, LINERATE).is_ok(), 0), - jdac_common::PRINT_STATUS => { board_artiq::ad9154::status(_dacno); (true, 0) }, - jdac_common::PRBS => (board_artiq::ad9154::prbs(_dacno).is_ok(), 0), - jdac_common::STPL => (board_artiq::ad9154::stpl(_dacno, 4, 2).is_ok(), 0), - jdac_common::SYSREF_DELAY_DAC => { board_artiq::hmc830_7043::hmc7043::sysref_delay_dac(_dacno, _param); (true, 0) }, - jdac_common::SYSREF_SLIP => { board_artiq::hmc830_7043::hmc7043::sysref_slip(); (true, 0) }, - jdac_common::SYNC => { - match board_artiq::ad9154::sync(_dacno) { - Ok(false) => (true, 0), - Ok(true) => (true, 1), - Err(e) => { - error!("DAC sync failed: {}", e); - (false, 0) - } - } - }, - jdac_common::DDMTD_SYSREF_RAW => (true, jdac_common::measure_ddmdt_phase_raw() as u8), - jdac_common::DDMTD_SYSREF => (true, jdac_common::measure_ddmdt_phase() as u8), - _ => (false, 0) - } - }; - #[cfg(not(has_ad9154))] - let (succeeded, retval) = (false, 0); - drtioaux::send(0, - &drtioaux::Packet::JdacBasicReply { succeeded: succeeded, retval: retval }) - } - _ => { warn!("received unexpected aux packet"); Ok(()) @@ -529,17 +486,6 @@ pub extern fn main() -> i32 { wrpll::diagnostics(); init_rtio_crg(); - #[cfg(has_hmc830_7043)] - /* must be the first SPI init because of HMC830 SPI mode selection */ - hmc830_7043::init().expect("cannot initialize HMC830/7043"); - #[cfg(has_ad9154)] - { - jdac_common::init_ddmtd().expect("failed to initialize SYSREF DDMTD core"); - for dacno in 0..csr::CONFIG_AD9154_COUNT { - board_artiq::ad9154::reset_and_detect(dacno as u8).expect("AD9154 DAC not detected"); - } - } - #[cfg(has_drtio_routing)] let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()]; #[cfg(not(has_drtio_routing))] diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index b24f63315..f38f2c26b 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -309,34 +309,6 @@ class PeripheralManager: return next(channel) - def process_novogorny(self, rtio_offset, peripheral): - self.gen(""" - device_db["spi_{name}_adc"] = {{ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {{"channel": 0x{adc_channel:06x}}} - }} - device_db["ttl_{name}_cnv"] = {{ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {{"channel": 0x{cnv_channel:06x}}}, - }} - device_db["{name}"] = {{ - "type": "local", - "module": "artiq.coredevice.novogorny", - "class": "Novogorny", - "arguments": {{ - "spi_adc_device": "spi_{name}_adc", - "cnv_device": "ttl_{name}_cnv" - }} - }}""", - name=self.get_name("novogorny"), - adc_channel=rtio_offset, - cnv_channel=rtio_offset + 1) - return 2 - def process_sampler(self, rtio_offset, peripheral): self.gen(""" device_db["spi_{name}_adc"] = {{ diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 532d1da92..a4892924f 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -25,12 +25,10 @@ def get_argparser(): Valid actions: * gateware: write main gateware bitstream to flash - * rtm_gateware: write RTM gateware bitstream to flash * bootloader: write bootloader to flash * storage: write storage image to flash * firmware: write firmware to flash * load: load main gateware bitstream into device (volatile but fast) - * rtm_load: load RTM gateware bitstream into device * erase: erase flash memory * start: trigger the target to (re)load its gateware bitstream from flash @@ -61,7 +59,7 @@ Prerequisites: help="SSH host to jump through") parser.add_argument("-t", "--target", default="kasli", help="target board, default: %(default)s, one of: " - "kasli sayma metlino kc705") + "kasli kc705") parser.add_argument("-I", "--preinit-command", default=[], action="append", help="add a pre-initialization OpenOCD command. " "Useful for selecting a board when several are connected.") @@ -69,8 +67,6 @@ Prerequisites: parser.add_argument("-d", "--dir", default=None, help="look for board binaries in this directory") parser.add_argument("--srcbuild", help="board binaries directory is laid out as a source build tree", default=False, action="store_true") - parser.add_argument("--no-rtm-jtag", help="do not attempt JTAG to the RTM", - default=False, action="store_true") parser.add_argument("action", metavar="ACTION", nargs="*", default=[], help="actions to perform, default: flash everything") @@ -229,76 +225,6 @@ class ProgrammerXC7(Programmer): "xc7_program xc7.tap") -class ProgrammerAMCRTM(Programmer): - _sector_size = 0x10000 - - def __init__(self, client, preinit_script): - Programmer.__init__(self, client, preinit_script) - - add_commands(self._board_script, - "source {}".format(self._transfer_script("fpga/xilinx-xadc.cfg")), - - "interface ftdi", - "ftdi_device_desc \"Quad RS232-HS\"", - "ftdi_vid_pid 0x0403 0x6011", - "ftdi_channel 0", - # EN_USB_JTAG on ADBUS7: out, high - # nTRST on ADBUS4: out, high, but R46 is DNP - "ftdi_layout_init 0x0098 0x008b", - "reset_config none", - "adapter_khz 5000", - "transport select jtag", - # tap 0, pld 0 - "source {}".format(self._transfer_script("cpld/xilinx-xc7.cfg")), - # tap 1, pld 1 - "set CHIP XCKU040", - "source {}".format(self._transfer_script("cpld/xilinx-xcu.cfg"))) - self.add_flash_bank("spi0", "xcu", index=0) - self.add_flash_bank("spi1", "xcu", index=1) - - add_commands(self._script, "echo \"RTM FPGA XADC:\"", "xadc_report xc7.tap") - add_commands(self._script, "echo \"AMC FPGA XADC:\"", "xadc_report xcu.tap") - - def load_proxy(self): - self.load(find_proxy_bitfile("bscan_spi_xcku040.bit"), pld=1) - - def start(self): - add_commands(self._script, "xcu_program xcu.tap") - - -class ProgrammerAMC(Programmer): - _sector_size = 0x10000 - - def __init__(self, client, preinit_script): - Programmer.__init__(self, client, preinit_script) - - add_commands(self._board_script, - "source {}".format(self._transfer_script("fpga/xilinx-xadc.cfg")), - - "interface ftdi", - "ftdi_device_desc \"Quad RS232-HS\"", - "ftdi_vid_pid 0x0403 0x6011", - "ftdi_channel 0", - # EN_USB_JTAG on ADBUS7: out, high - # nTRST on ADBUS4: out, high, but R46 is DNP - "ftdi_layout_init 0x0098 0x008b", - "reset_config none", - "adapter_khz 5000", - "transport select jtag", - "set CHIP XCKU040", - "source {}".format(self._transfer_script("cpld/xilinx-xcu.cfg"))) - self.add_flash_bank("spi0", "xcu", index=0) - self.add_flash_bank("spi1", "xcu", index=1) - - add_commands(self._script, "echo \"AMC FPGA XADC:\"", "xadc_report xcu.tap") - - def load_proxy(self): - self.load(find_proxy_bitfile("bscan_spi_xcku040.bit"), pld=0) - - def start(self): - add_commands(self._script, "xcu_program xcu.tap") - - def main(): args = get_argparser().parse_args() common_args.init_logger_from_args(args) @@ -311,21 +237,6 @@ def main(): "storage": ("spi0", 0x440000), "firmware": ("spi0", 0x450000), }, - "sayma": { - "programmer": ProgrammerAMCRTM, - "gateware": ("spi0", 0x000000), - "bootloader": ("spi1", 0x000000), - "storage": ("spi1", 0x040000), - "firmware": ("spi1", 0x050000), - "rtm_gateware": ("spi1", 0x200000), - }, - "metlino": { - "programmer": ProgrammerAMC, - "gateware": ("spi0", 0x000000), - "bootloader": ("spi1", 0x000000), - "storage": ("spi1", 0x040000), - "firmware": ("spi1", 0x050000), - }, "kc705": { "programmer": partial(ProgrammerXC7, board="kc705", proxy="bscan_spi_xc7k325t.bit"), "gateware": ("spi0", 0x000000), @@ -336,32 +247,21 @@ def main(): }[args.target] if not args.action: - if args.target == "sayma": - args.action = "gateware rtm_gateware bootloader firmware start".split() - else: - args.action = "gateware bootloader firmware start".split() + args.action = "gateware bootloader firmware start".split() needs_artifacts = any( action in args.action - for action in ["gateware", "rtm_gateware", "bootloader", "firmware", "load", "rtm_load"]) + for action in ["gateware", "bootloader", "firmware", "load"]) if needs_artifacts and args.dir is None: raise ValueError("the directory containing the binaries need to be specified using -d.") binary_dir = args.dir - if binary_dir is not None: - rtm_binary_dir = os.path.join(binary_dir, "rtm") - else: - rtm_binary_dir = None if args.host is None: client = LocalClient() else: client = SSHClient(args.host, args.jump) - if args.target == "sayma" and args.no_rtm_jtag: - programmer_cls = ProgrammerAMC - else: - programmer_cls = config["programmer"] - programmer = programmer_cls(client, preinit_script=args.preinit_command) + programmer = config["programmer"](client, preinit_script=args.preinit_command) def artifact_path(this_binary_dir, *path_filename): if args.srcbuild: @@ -372,7 +272,7 @@ def main(): *_, filename = path_filename return os.path.join(this_binary_dir, filename) - def convert_gateware(bit_filename, header=False): + def convert_gateware(bit_filename): bin_handle, bin_filename = tempfile.mkstemp( prefix="artiq_", suffix="_" + os.path.basename(bit_filename)) with open(bit_filename, "rb") as bit_file, \ @@ -380,12 +280,6 @@ def main(): if header: bin_file.write(b"\x00"*8) bit2bin(bit_file, bin_file) - if header: - magic = 0x5352544d # "SRTM", see sayma_rtm target - length = bin_file.tell() - 8 - bin_file.seek(0) - bin_file.write(magic.to_bytes(4, byteorder="little")) - bin_file.write(length.to_bytes(4, byteorder="little")) atexit.register(lambda: os.unlink(bin_filename)) return bin_filename @@ -394,11 +288,6 @@ def main(): gateware_bin = convert_gateware( artifact_path(binary_dir, "gateware", "top.bit")) programmer.write_binary(*config["gateware"], gateware_bin) - elif action == "rtm_gateware": - rtm_gateware_bin = convert_gateware( - artifact_path(rtm_binary_dir, "gateware", "top.bit"), header=True) - programmer.write_binary(*config["rtm_gateware"], - rtm_gateware_bin) elif action == "bootloader": bootloader_bin = artifact_path(binary_dir, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin) @@ -418,23 +307,12 @@ def main(): "Found firmware files: {}".format(" ".join(firmware_fbis))) programmer.write_binary(*config["firmware"], firmware_fbis[0]) elif action == "load": - if args.target == "sayma": - gateware_bit = artifact_path(binary_dir, "gateware", "top.bit") - programmer.load(gateware_bit, 1) - else: - gateware_bit = artifact_path(binary_dir, "gateware", "top.bit") - programmer.load(gateware_bit, 0) - elif action == "rtm_load": - rtm_gateware_bit = artifact_path(rtm_binary_dir, "gateware", "top.bit") - programmer.load(rtm_gateware_bit, 0) + gateware_bit = artifact_path(binary_dir, "gateware", "top.bit") + programmer.load(gateware_bit, 0) elif action == "start": programmer.start() elif action == "erase": - if args.target == "sayma" or args.target == "metlino": - programmer.erase_flash("spi0") - programmer.erase_flash("spi1") - else: - programmer.erase_flash("spi0") + programmer.erase_flash("spi0") else: raise ValueError("invalid action", action) diff --git a/artiq/gateware/dsp/__init__.py b/artiq/gateware/dsp/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/artiq/gateware/dsp/accu.py b/artiq/gateware/dsp/accu.py deleted file mode 100644 index 79e297883..000000000 --- a/artiq/gateware/dsp/accu.py +++ /dev/null @@ -1,112 +0,0 @@ -from migen import * -from misoc.interconnect.stream import Endpoint - - -class Accu(Module): - def __init__(self, width, meta=[]): - self.i = Endpoint([("p", width), ("f", width), ("clr", 1)]) - self.o = Endpoint([("z", width)]) - self.latency = 1 - - ### - - f = Signal.like(self.i.f) - p = Signal.like(self.i.p) - self.comb += self.i.ack.eq(~self.o.stb | self.o.ack) - self.sync += [ - If(self.o.ack, - self.o.stb.eq(0), - ), - If(self.i.ack, - self.o.stb.eq(1), - If(self.i.stb, - self.o.z.eq(self.i.p + Mux(self.i.clr, 0, self.o.z + p)), - f.eq(self.i.f), - p.eq(self.i.f - self.i.p), - ).Else( - self.o.z.eq(self.o.z + f), - ) - ) - ] - - -class MCM(Module): - def __init__(self, width, constants): - n = len(constants) - self.i = i = Signal(width) - self.o = o = [Signal.like(self.i) for i in range(n)] - - ### - - # TODO: improve MCM - assert range(n) == constants - assert n <= 9 - - if n > 0: - self.comb += o[0].eq(0) - if n > 1: - self.comb += o[1].eq(i) - if n > 2: - self.comb += o[2].eq(i << 1) - if n > 3: - self.comb += o[3].eq(i + (i << 1)) - if n > 4: - self.comb += o[4].eq(i << 2) - if n > 5: - self.comb += o[5].eq(i + (i << 2)) - if n > 6: - self.comb += o[6].eq(o[3] << 1) - if n > 7: - self.comb += o[7].eq((i << 3) - i) - if n > 8: - self.comb += o[8].eq(i << 3) - - -class PhasedAccu(Module): - def __init__(self, width, parallelism=8): - self.i = Endpoint([("p", width), ("f", width), ("clr", 1)]) - self.o = Endpoint([("z{}".format(i), width) for i in - range(parallelism)]) - self.parallelism = parallelism - self.latency = 2 - - ### - - a = MCM(width, range(parallelism + 1)) - self.submodules += a - z = [Signal(width, reset_less=True) for i in range(parallelism)] - o = self.o.payload.flatten() - load = Signal(reset_less=True) - clr = Signal(reset_less=True) - p = Signal.like(self.i.p) - f = Signal.like(self.i.f, reset_less=True) - fp = Signal.like(self.i.f) - self.comb += [ - self.i.ack.eq(self.o.ack), - a.i.eq(self.i.f), - ] - - self.sync += [ - If(self.o.ack, - self.o.stb.eq(0), - ), - If(~self.o.stb | self.o.ack, - self.o.stb.eq(1), - If(load, - load.eq(0), - [oi.eq(Mux(clr, 0, o[0] + fp) + zi) - for oi, zi in zip(o, z)], - fp.eq(f), - ).Else( - [oi.eq(oi + fp) for oi in o], - ), - ), - If(self.i.stb & self.i.ack, - [zi.eq(self.i.p - Mux(self.i.clr, 0, p) + aoi) - for zi, aoi in zip(z, a.o)], - clr.eq(self.i.clr), - p.eq(self.i.p), - f.eq(a.o[parallelism]), - load.eq(1), - ), - ] diff --git a/artiq/gateware/dsp/fir.py b/artiq/gateware/dsp/fir.py deleted file mode 100644 index 002487e32..000000000 --- a/artiq/gateware/dsp/fir.py +++ /dev/null @@ -1,172 +0,0 @@ -from math import floor -from operator import add -from functools import reduce -from collections import namedtuple - -import numpy as np - -from migen import * - - -def halfgen4(width, n, df=1e-3): - """ - http://recycle.lbl.gov/~ldoolitt/halfband - - params: - * `up` is the passband/stopband width, as a fraction of - input sampling rate - * `n is the order of half-band filter to generate - returns: - * `a` is the full set of FIR coefficients, `4*n-1` long. - implement wisely. - """ - - npt = n*40 - wmax = 2*np.pi*width - wfit = (1 - np.linspace(0, 1, npt)[:, None]**2)*wmax - - target = .5*np.ones_like(wfit) - basis = np.cos(wfit*np.arange(1, 2*n, 2)) - weight = np.ones_like(wfit) - - f0 = None - - for i in range(40): - l = np.linalg.pinv(basis*weight)@(target*weight) - err = np.fabs(basis@l - .5) - f = np.max(err)/np.mean(err) - if f0 and (f0 - f)/(f0 + f) < df/2: - break - f0 = f - weight[err > (1 - df)*np.max(err)] *= 1 + 1.5/(i + 11) - a = np.c_[l, np.zeros_like(l)].ravel()[:-1] - a = np.r_[a[::-1], 1, a]/2 - return a - - -_Widths = namedtuple("_Widths", "A B P") - -_widths = { - "DSP48E1": _Widths(25, 18, 48), -} - - -class ParallelFIR(Module): - """Full-rate parallelized finite impulse response filter. - - Tries to use transposed form as much as possible. - - :param coefficients: tap coefficients (normalized to 1.), - increasing delay. - :param parallelism: number of samples per cycle. - :param width: bit width of input and output. - :param arch: architecture (default: "DSP48E1"). - """ - def __init__(self, coefficients, parallelism, width=16, - arch="DSP48E1", cull_delays=()): - self.width = width - self.parallelism = p = parallelism - n = len(coefficients) - # input and output: old to new, decreasing delay - self.i = [Signal((width, True)) for i in range(p)] - self.o = [Signal((width, True), reset_less=True) for i in range(p)] - self.latency = (n + 1)//2//p + 2 - w = _widths[arch] - - c_max = max(abs(c) for c in coefficients) - c_shift = bits_for(floor((1 << w.B - 2) / c_max)) - self.coefficients = cs = [int(round(c*(1 << c_shift))) - for c in coefficients] - assert max(bits_for(c) for c in cs) <= w.B - max_out = sum(abs(c)*(1 << w.A - 1) for c in cs) - assert max_out <= (1 << w.P - 1) - 1, (bits_for(max_out), w) - - ### - - # Delay line: increasing delay - x = [Signal((w.A, True), reset_less=True) for _ in range(n + p - 1)] - - for xi, xj in zip(x, self.i[::-1]): - self.comb += xi.eq(xj) - for xi, xj in zip(x[len(self.i):], x): - self.sync += xi.eq(xj) - - for delay in range(p): - o = Signal((w.P, True), reset_less=True) - self.sync += self.o[delay].eq(o >> c_shift) - # Make products - tap = delay - for i, c in enumerate(cs): - # simplify for halfband and symmetric filters - if not c or c in cs[:i]: - continue - js = [j + p - 1 for j, cj in enumerate(cs) if cj == c] - m = Signal.like(o) - o0, o = o, Signal.like(o) - q = Signal.like(x[0]) - if tap + p <= js[0]: - self.sync += o0.eq(o + m) - tap += p - else: - self.comb += o0.eq(o + m) - assert min(js) - tap >= 0 - js = [j for j in js - if (p - 1 - j - tap) % p not in cull_delays] - if not js: - continue - self.comb += q.eq(reduce(add, [x[j - tap] for j in js])) - self.sync += m.eq(c*q) - # symmetric rounding - if c_shift > 1 and delay not in cull_delays: - self.comb += o.eq((1 << c_shift - 1) - 1) - - -class FIR(ParallelFIR): - def __init__(self, *args, **kwargs): - super().__init__(self, *args, parallelism=1, **kwargs) - self.i = self.i[0] - self.o = self.o[0] - - -def halfgen4_cascade(rate, width, order=None): - """Generate coefficients for cascaded half-band filters. - - Coefficients are normalized to a gain of two per stage to compensate for - the zero stuffing. - - :param rate: upsampling rate. power of two - :param width: passband/stopband width in units of input sampling rate. - :param order: highest order, defaults to :param:`rate`""" - if order is None: - order = rate - coeff = [] - p = 1 - while p < rate: - p *= 2 - coeff.append(2*halfgen4(width*p/rate/2, order*p//rate)) - return coeff - - -class ParallelHBFUpsampler(Module): - """Parallel, power-of-two, half-band, cascading upsampler. - - Coefficients should be normalized to overall gain of 2 - (highest/center coefficient being 1).""" - def __init__(self, coefficients, width=16, **kwargs): - self.parallelism = 1 # accumulate - self.latency = 0 # accumulate - self.width = width - self.i = Signal((width, True)) - - ### - - i = [self.i] - for coeff in coefficients: - self.parallelism *= 2 - hbf = ParallelFIR(coeff, self.parallelism, width=width, - cull_delays={0}, **kwargs) - self.submodules += hbf - self.comb += [a.eq(b) for a, b in zip(hbf.i[1::2], i)] - i = hbf.o - self.latency += hbf.latency - self.o = i diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py deleted file mode 100644 index e0e9d1db4..000000000 --- a/artiq/gateware/dsp/sawg.py +++ /dev/null @@ -1,220 +0,0 @@ -from collections import namedtuple - -from migen import * -from misoc.interconnect.stream import Endpoint -from misoc.cores.cordic import Cordic - -from .accu import PhasedAccu -from .tools import eqh, SatAddMixin -from .spline import Spline -from .fir import ParallelHBFUpsampler, halfgen4_cascade - - -_Widths = namedtuple("_Widths", "t a p f") -_Orders = namedtuple("_Orders", "a p f") - - -class SplineParallelDUC(Module): - def __init__(self, widths, orders, parallelism=1, **kwargs): - self.parallelism = parallelism - self.widths = widths - p = Spline(order=orders.p, width=widths.p) - f = Spline(order=orders.f, width=widths.f) - self.f = f.tri(widths.t) - self.p = p.tri(widths.t) - self.submodules += p, f - self.ce = Signal(reset=1) - self.clr = Signal() - - ### - accu = PhasedAccu(len(self.f.a0), parallelism) - cordic = [Cordic(width=widths.a, widthz=len(self.p.a0), guard=None, - eval_mode="pipelined") for i in range(parallelism)] - self.submodules += accu, cordic - - self.xi = [c.xi for c in cordic] - self.yi = [c.yi for c in cordic] - self.xo = [c.xo for c in cordic] - self.yo = [c.yo for c in cordic] - self.latency = cordic[0].latency - self.gain = cordic[0].gain - self.f.latency += accu.latency + self.latency - self.p.latency += accu.latency + self.latency - - ### - - assert p.latency == f.latency - self.comb += [ - p.o.ack.eq(self.ce), - f.o.ack.eq(self.ce), - eqh(accu.i.f, f.o.a0), - eqh(accu.i.p, p.o.a0), - accu.i.stb.eq(p.o.stb | f.o.stb), - accu.o.ack.eq(1), - [eqh(c.zi, zi) for c, zi in - zip(cordic, accu.o.payload.flatten())] - ] - - assert p.latency == 1 - accu.i.clr.reset_less = True - self.sync += [ - accu.i.clr.eq(0), - If(p.i.stb, - accu.i.clr.eq(self.clr), - ), - ] - - -class SplineParallelDDS(SplineParallelDUC): - def __init__(self, widths, orders, **kwargs): - a = Spline(order=orders.a, width=widths.a) - self.a = a.tri(widths.t) - self.submodules += a - super().__init__(widths._replace(a=len(self.a.a0)), orders, **kwargs) - - self.a.latency += self.latency - - ### - - self.comb += [ - a.o.ack.eq(self.ce), - [eqh(x, a.o.a0) for x in self.xi], - [y.eq(0) for y in self.yi], - ] - del self.xi - del self.yi - - -class Config(Module): - def __init__(self, width, cordic_gain): - self.clr = Signal(3, reset=0b111) - self.iq_en = Signal(2, reset=0b01) - self.limits = [[Signal((width, True)), Signal((width, True))] - for i in range(2)] - limit = (1 << width - 1) - 1 - limit_cordic = int(limit/cordic_gain) - self.limits[0][0].reset = Constant(-limit, (width, True)) - self.limits[0][1].reset = Constant(limit, (width, True)) - self.limits[1][0].reset = Constant(-limit_cordic, (width, True)) - self.limits[1][1].reset = Constant(limit_cordic, (width, True)) - # TODO make persistent, add read-out/notification/clear - self.clipped = [Signal(2) for i in range(2)] - self.i = Endpoint([("addr", bits_for(4 + 2*len(self.limits) - 1)), - ("data", width)]) - assert len(self.i.addr) == 3 - self.ce = Signal() - - ### - - div = Signal(16, reset=0) - n = Signal.like(div) - - self.comb += self.ce.eq(n == 0) - self.sync += [ - n.eq(n - 1), - If(self.ce, - n.eq(div), - ) - ] - - pad = Signal() - - reg = Array(sum(self.limits, - [Cat(div, n), self.clr, self.iq_en, pad])) - - self.comb += self.i.ack.eq(1) - self.sync += [ - If(self.i.stb, - reg[self.i.addr].eq(self.i.data), - ), - ] - - -class Channel(Module, SatAddMixin): - def __init__(self, width=16, parallelism=4, widths=None, orders=None): - if orders is None: - orders = _Orders(a=4, f=2, p=1) - if widths is None: - widths = _Widths(t=width, a=orders.a*width, p=orders.p*width, - f=(orders.f + 2)*width) - - self.submodules.a1 = a1 = SplineParallelDDS(widths, orders) - self.submodules.a2 = a2 = SplineParallelDDS(widths, orders) - coeff = halfgen4_cascade(parallelism, width=.4, order=8) - hbf = [ParallelHBFUpsampler(coeff, width=width + 1) for i in range(2)] - self.submodules.b = b = SplineParallelDUC( - widths._replace(a=len(hbf[0].o[0]), f=widths.f - width), orders, - parallelism=parallelism) - cfg = Config(width, b.gain) - u = Spline(width=widths.a, order=orders.a) - self.submodules += cfg, u, hbf - self.u = u.tri(widths.t) - self.i = [cfg.i, self.u, a1.a, a1.f, a1.p, a2.a, a2.f, a2.p, b.f, b.p] - self.i_names = "cfg u a1 f1 p1 a2 f2 p2 f0 p0".split() - self.i_named = dict(zip(self.i_names, self.i)) - self.y_in = [Signal.like(b.yo[0]) for i in range(parallelism)] - self.o = [Signal((width, True), reset_less=True) - for i in range(parallelism)] - self.widths = widths - self.orders = orders - self.parallelism = parallelism - self.cordic_gain = a2.gain*b.gain - - self.u.latency += 1 # self.o - b.p.latency += 1 # self.o - b.f.latency += 1 # self.o - a_latency_delta = hbf[0].latency + b.latency + 2 # hbf.i, self.o - for a in a1, a2: - a.a.latency += a_latency_delta - a.p.latency += a_latency_delta - a.f.latency += a_latency_delta - - self.latency = max(_.latency for _ in self.i[1:]) - for i in self.i[1:]: - i.latency -= self.latency - assert i.latency <= 0 - cfg.i.latency = 0 - - ### - - self.comb += [ - a1.ce.eq(cfg.ce), - a2.ce.eq(cfg.ce), - b.ce.eq(cfg.ce), - u.o.ack.eq(cfg.ce), - Cat(b.clr, a1.clr, a2.clr).eq(cfg.clr), - [i.eq(j) for i, j in zip(b.xi, hbf[0].o)], - [i.eq(j) for i, j in zip(b.yi, hbf[1].o)], - ] - hbf[0].i.reset_less = True - hbf[1].i.reset_less = True - self.sync += [ - hbf[0].i.eq(self.sat_add((a1.xo[0], a2.xo[0]), - width=len(hbf[0].i), - limits=cfg.limits[1], clipped=cfg.clipped[1])), - hbf[1].i.eq(self.sat_add((a1.yo[0], a2.yo[0]), - width=len(hbf[1].i), - limits=cfg.limits[1])), - ] - # wire up outputs and q_{i,o} exchange - for o, x, y in zip(self.o, b.xo, self.y_in): - o_offset = Signal.like(o) - o_x = Signal.like(x) - o_y = Signal.like(y) - self.comb += [ - o_offset.eq(u.o.a0[-len(o):]), - If(cfg.iq_en[0], - o_x.eq(x) - ), - If(cfg.iq_en[1], - o_y.eq(y) - ), - ] - self.sync += [ - o.eq(self.sat_add((o_offset, o_x, o_y), - width=len(o), - limits=cfg.limits[0], clipped=cfg.clipped[0])), - ] - - def connect_y(self, buddy): - self.comb += [i.eq(j) for i, j in zip(buddy.y_in, self.b.yo)] diff --git a/artiq/gateware/dsp/spline.py b/artiq/gateware/dsp/spline.py deleted file mode 100644 index 8185ae856..000000000 --- a/artiq/gateware/dsp/spline.py +++ /dev/null @@ -1,47 +0,0 @@ -from migen import * -from misoc.interconnect.stream import Endpoint - - -class Spline(Module): - def __init__(self, order, width, step=1, time_width=None): - if not (step == 1 or order <= 2): - raise ValueError("For non-linear splines, " - "`step` needs to be one.") - layout = [("a{}".format(i), (width, True)) for i in range(order)] - self.i = Endpoint(layout) - self.o = Endpoint(layout) - self.latency = 1 - - ### - - o = self.o.payload.flatten() - - self.comb += self.i.ack.eq(~self.o.stb | self.o.ack) - self.sync += [ - If(self.o.ack, - self.o.stb.eq(0), - ), - If(self.i.ack, - self.o.stb.eq(1), - [o[i].eq(o[i] + (o[i + 1] << log2_int(step))) - for i in range(order - 1)], - If(self.i.stb, - self.o.payload.eq(self.i.payload), - ), - ), - ] - - def tri(self, time_width): - layout = [(name, (length - i*time_width, signed)) - for i, (name, (length, signed), dir) in - enumerate(self.i.payload.layout[::-1])] - layout.reverse() - i = Endpoint(layout) - i.latency = self.latency - self.comb += [ - self.i.stb.eq(i.stb), - i.ack.eq(self.i.ack), - [i0[-len(i1):].eq(i1) for i0, i1 in - zip(self.i.payload.flatten(), i.payload.flatten())] - ] - return i diff --git a/artiq/gateware/dsp/tools.py b/artiq/gateware/dsp/tools.py deleted file mode 100644 index c198d1706..000000000 --- a/artiq/gateware/dsp/tools.py +++ /dev/null @@ -1,69 +0,0 @@ -from operator import add -from functools import reduce - -from migen import * - - -class Delay(Module): - def __init__(self, i, delay, o=None): - if isinstance(i, (int, tuple)): - z = [Signal(i) for j in range(delay + 1)] - elif isinstance(i, list): - z = [Record(i) for j in range(delay + 1)] - elif isinstance(i, Record): - z = [Record(i.layout) for j in range(delay + 1)] - else: - z = [Signal.like(i) for j in range(delay + 1)] - self.i = z[0] - self.o = z[-1] - if not isinstance(i, (int, list, tuple)): - self.comb += self.i.eq(i) - if o is not None: - self.comb += o.eq(self.o) - self.latency = delay - self.sync += [z[j + 1].eq(z[j]) for j in range(delay)] - - -def eqh(a, b): - return a[-len(b):].eq(b[-len(a):]) - - -class SatAddMixin: - """Signed saturating addition mixin""" - def sat_add(self, a, width, limits=None, clipped=None): - a = list(a) - # assert all(value_bits_sign(ai)[1] for ai in a) - max_width = max(value_bits_sign(ai)[0] for ai in a) - carry = log2_int(len(a), need_pow2=False) - full = Signal((max_width + carry, True)) - limited = Signal((width, True)) - carry = len(full) - width - assert carry >= 0 - clip = Signal(2) - sign = Signal() - if clipped is not None: - self.comb += clipped.eq(clip) - self.comb += [ - full.eq(reduce(add, a)), - sign.eq(full[-1]), - limited.eq(full) - ] - if limits is None: - self.comb += [ - If(full[-1-carry:] != Replicate(sign, carry + 1), - clip.eq(Cat(sign, ~sign)), - limited.eq(Cat(Replicate(~sign, width - 1), sign)), - ) - ] - else: - self.comb += [ - If(full < limits[0], - clip.eq(0b01), - limited.eq(limits[0]) - ), - If(full > limits[1], - clip.eq(0b10), - limited.eq(limits[1]), - ) - ] - return limited diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 7f5fe3fdf..f5cfde956 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -275,53 +275,6 @@ class Sampler(_EEM): target.specials += DifferentialOutput(1, sdr.p, sdr.n) -class Novogorny(_EEM): - @staticmethod - def io(eem, iostandard): - return [ - ("novogorny{}_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("cs_n", Pins( - _eem_pin(eem, 3, "p"), _eem_pin(eem, 4, "p"))), - iostandard(eem), - ), - ("novogorny{}_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("cs_n", Pins( - _eem_pin(eem, 3, "n"), _eem_pin(eem, 4, "n"))), - iostandard(eem), - ), - ] + [ - ("novogorny{}_{}".format(eem, sig), 0, - Subsignal("p", Pins(_eem_pin(j, i, "p"))), - Subsignal("n", Pins(_eem_pin(j, i, "n"))), - iostandard(j) - ) for i, j, sig in [ - (5, eem, "cnv"), - (6, eem, "busy"), - (7, eem, "scko"), - ] - ] - - @classmethod - def add_std(cls, target, eem, ttl_out_cls, iostandard=default_iostandard): - cls.add_extension(target, eem, iostandard=iostandard) - - phy = spi2.SPIMaster(target.platform.request("novogorny{}_spi_p".format(eem)), - target.platform.request("novogorny{}_spi_n".format(eem))) - target.submodules += phy - target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16)) - - pads = target.platform.request("novogorny{}_cnv".format(eem)) - phy = ttl_out_cls(pads.p, pads.n) - target.submodules += phy - target.rtio_channels.append(rtio.Channel.from_phy(phy)) - - class Zotino(_EEM): @staticmethod def io(eem, iostandard): diff --git a/artiq/gateware/eem_7series.py b/artiq/gateware/eem_7series.py index 232150211..cb9320861 100644 --- a/artiq/gateware/eem_7series.py +++ b/artiq/gateware/eem_7series.py @@ -34,13 +34,6 @@ def peripheral_urukul(module, peripheral, **kwargs): sync_gen_cls, **kwargs) -def peripheral_novogorny(module, peripheral, **kwargs): - if len(peripheral["ports"]) != 1: - raise ValueError("wrong number of ports") - eem.Novogorny.add_std(module, peripheral["ports"][0], - ttl_serdes_7series.Output_8X, **kwargs) - - def peripheral_sampler(module, peripheral, **kwargs): if len(peripheral["ports"]) == 1: port, port_aux = peripheral["ports"][0], None @@ -120,7 +113,6 @@ def peripheral_hvamp(module, peripheral, **kwargs): peripheral_processors = { "dio": peripheral_dio, "urukul": peripheral_urukul, - "novogorny": peripheral_novogorny, "sampler": peripheral_sampler, "suservo": peripheral_suservo, "zotino": peripheral_zotino, diff --git a/artiq/gateware/fmcdio_vhdci_eem.py b/artiq/gateware/fmcdio_vhdci_eem.py deleted file mode 100644 index 0296efe8e..000000000 --- a/artiq/gateware/fmcdio_vhdci_eem.py +++ /dev/null @@ -1,29 +0,0 @@ -from migen.build.generic_platform import * - -from artiq.coredevice.fmcdio_vhdci_eem import * - - -io = [ - ("fmcdio_dirctl", 0, - Subsignal("clk", Pins("LPC:LA32_N")), - Subsignal("ser", Pins("LPC:LA33_P")), - Subsignal("latch", Pins("LPC:LA32_P")), - IOStandard("LVCMOS18") - ), -] - -def _get_connectors(): - connectors = [] - for i in range(4): - connections = dict() - for j, pair in enumerate(eem_fmc_connections[i]): - for pn in "n", "p": - cc = "cc_" if j == 0 else "" - lpc_cc = "CC_" if eem_fmc_connections[i][j] in (0, 1, 17, 18) else "" - connections["d{}_{}{}".format(j, cc, pn)] = \ - "LPC:LA{:02d}_{}{}".format(pair, lpc_cc, pn.upper()) - connectors.append(("eem{}".format(i), connections)) - return connectors - - -connectors = _get_connectors() diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py deleted file mode 100644 index d05d6432f..000000000 --- a/artiq/gateware/jesd204_tools.py +++ /dev/null @@ -1,290 +0,0 @@ -from collections import namedtuple - -from migen import * -from migen.genlib.cdc import MultiReg, BusSynchronizer -from migen.genlib.resetsync import AsyncResetSynchronizer -from misoc.interconnect.csr import * - -from jesd204b.common import (JESD204BTransportSettings, - JESD204BPhysicalSettings, - JESD204BSettings) -from jesd204b.phy.gth import (GTHChannelPLL as JESD204BGTHChannelPLL, - GTHQuadPLL as JESD204BGTHQuadPLL, - GTHTransmitter as JESD204BGTHTransmitter, - GTHInit as JESD204BGTHInit, - GTHTransmitterInterconnect as JESD204BGTHTransmitterInterconnect) -from jesd204b.phy import JESD204BPhyTX -from jesd204b.core import JESD204BCoreTX -from jesd204b.core import JESD204BCoreTXControl - - -class UltrascaleCRG(Module, AutoCSR): - linerate = int(6e9) # linerate = 20*data_rate*4/8 = data_rate*10 - # data_rate = dac_rate/interp_factor - refclk_freq = int(150e6) - fabric_freq = int(125e6) - - def __init__(self, platform, use_rtio_clock=False): - self.jreset = CSRStorage(reset=1) - self.refclk = Signal() - self.clock_domains.cd_jesd = ClockDomain() - - refclk2 = Signal() - refclk_pads = platform.request("dac_refclk", 0) - platform.add_period_constraint(refclk_pads.p, 1e9/self.refclk_freq) - self.specials += [ - Instance("IBUFDS_GTE3", i_CEB=0, p_REFCLK_HROW_CK_SEL=0b00, - i_I=refclk_pads.p, i_IB=refclk_pads.n, - o_O=self.refclk, o_ODIV2=refclk2), - AsyncResetSynchronizer(self.cd_jesd, self.jreset.storage), - ] - - if use_rtio_clock: - self.cd_jesd.clk.attr.add("keep") - self.comb += self.cd_jesd.clk.eq(ClockSignal("rtio")) - else: - self.specials += Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk) - - -PhyPads = namedtuple("PhyPads", "txp txn") - - -class UltrascaleTX(Module, AutoCSR): - def __init__(self, platform, sys_crg, jesd_crg, dac, pll_type="cpll", tx_half=False): - # Note: In general, the choice between channel and quad PLLs can be made based on the "nominal operating ranges", which are (see UG576, Ch.2): - # CPLL: 2.0 - 6.25 GHz - # QPLL0: 9.8 - 16.375 GHz - # QPLL1: 8.0 - 13.0 GHz - # However, the exact frequency and/or linerate range should be checked according to the model and speed grade from their corresponding datasheets. - pll_cls = { - "cpll": JESD204BGTHChannelPLL, - "qpll": JESD204BGTHQuadPLL - }[pll_type] - ps = JESD204BPhysicalSettings(l=8, m=4, n=16, np=16) - ts = JESD204BTransportSettings(f=2, s=2, k=16, cs=0) - settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) - - jesd_pads = platform.request("dac_jesd", dac) - plls = [] - phys = [] - for i in range(len(jesd_pads.txp)): - pll = pll_cls( - jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate) - self.submodules += pll - plls.append(pll) - # QPLL quads - if pll_type == "qpll": - gthe3_common_cfgs = [] - for i in range(0, len(plls), 4): - # GTHE3_COMMON common signals - qpll_clk = Signal() - qpll_refclk = Signal() - qpll_reset = Signal() - qpll_lock = Signal() - # GTHE3_COMMON - self.specials += pll_cls.get_gthe3_common( - jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate, - qpll_clk, qpll_refclk, qpll_reset, qpll_lock) - gthe3_common_cfgs.append({ - "clk": qpll_clk, - "refclk": qpll_refclk, - "reset": qpll_reset, - "lock": qpll_lock - }) - # Per-channel PLL phys - for i, pll in enumerate(plls): - # PhyTX - phy = JESD204BPhyTX( - pll, jesd_crg.refclk, PhyPads(jesd_pads.txp[i], jesd_pads.txn[i]), - jesd_crg.fabric_freq, transceiver="gth", tx_half=tx_half) - phys.append(phy) - if tx_half: - platform.add_period_constraint(phy.transmitter.cd_tx_half.clk, - 80*1e9/jesd_crg.linerate) - platform.add_false_path_constraints( - sys_crg.cd_sys.clk, - jesd_crg.cd_jesd.clk, - phy.transmitter.cd_tx_half.clk) - else: - platform.add_period_constraint(phy.transmitter.cd_tx.clk, - 40*1e9/jesd_crg.linerate) - platform.add_false_path_constraints( - sys_crg.cd_sys.clk, - jesd_crg.cd_jesd.clk, - phy.transmitter.cd_tx.clk) - # CHANNEL & init interconnects - for i, (pll, phy) in enumerate(zip(plls, phys)): - # CPLLs: 1 init per channel - if pll_type == "cpll": - phy_channel_cfg = {} - # Connect reset/lock to init - pll_reset = pll.reset - pll_lock = pll.lock - self.submodules += JESD204BGTHTransmitterInterconnect( - pll_reset, pll_lock, phy.transmitter, phy.transmitter.init) - # QPLL: 4 inits and 4 channels per quad - elif pll_type == "qpll": - # Connect clk/refclk to CHANNEL - phy_cfg = gthe3_common_cfgs[int(i//4)] - phy_channel_cfg = { - "qpll_clk": phy_cfg["clk"], - "qpll_refclk": phy_cfg["refclk"] - } - # Connect reset/lock to init - pll_reset = phy_cfg["reset"] - pll_lock = phy_cfg["lock"] - if i % 4 == 0: - self.submodules += JESD204BGTHTransmitterInterconnect( - pll_reset, pll_lock, phy.transmitter, - [phys[j].transmitter.init for j in range(i, min(len(phys), i+4))]) - # GTHE3_CHANNEL - self.specials += JESD204BGTHTransmitter.get_gthe3_channel( - pll, phy.transmitter, **phy_channel_cfg) - - self.submodules.core = JESD204BCoreTX( - phys, settings, converter_data_width=64) - self.submodules.control = JESD204BCoreTXControl(self.core) - self.core.register_jsync(platform.request("dac_sync", dac)) - - -class DDMTDEdgeDetector(Module): - def __init__(self, i): - self.rising = Signal() - - history = Signal(4) - deglitched = Signal() - self.sync.helper += history.eq(Cat(history[1:], i)) - self.comb += deglitched.eq(i | history[0] | history[1] | history[2] | history[3]) - - deglitched_r = Signal() - self.sync.helper += [ - deglitched_r.eq(deglitched), - self.rising.eq(deglitched & ~deglitched_r) - ] - - -# See "Digital femtosecond time difference circuit for CERN's timing system" -# by P. Moreira and I. Darwazeh -class DDMTD(Module, AutoCSR): - def __init__(self, input_pads, rtio_clk_freq=150e6): - N = 64 - self.reset = CSRStorage(reset=1) - self.locked = CSRStatus() - self.dt = CSRStatus(N.bit_length()) - - # # # - - self.clock_domains.cd_helper = ClockDomain(reset_less=True) - helper_locked = Signal() - helper_fb = Signal() - helper_output = Signal() - - input_se = Signal() - beat1 = Signal() - beat2 = Signal() - self.specials += [ - Instance("MMCME2_BASE", - p_CLKIN1_PERIOD=1e9/rtio_clk_freq, - i_CLKIN1=ClockSignal("rtio"), - i_RST=self.reset.storage, - o_LOCKED=helper_locked, - - # VCO at 1200MHz with 150MHz RTIO frequency - p_CLKFBOUT_MULT_F=8.0, - p_DIVCLK_DIVIDE=1, - - o_CLKFBOUT=helper_fb, i_CLKFBIN=helper_fb, - - # helper PLL ratio: 64/65 (N=64) - p_CLKOUT0_DIVIDE_F=8.125, - o_CLKOUT0=helper_output, - ), - MultiReg(helper_locked, self.locked.status), - Instance("BUFG", i_I=helper_output, o_O=self.cd_helper.clk), - Instance("IBUFDS", i_I=input_pads.p, i_IB=input_pads.n, o_O=input_se), - Instance("FD", i_C=self.cd_helper.clk, i_D=input_se, o_Q=beat1, attr={("IOB", "TRUE")}), - Instance("FD", i_C=self.cd_helper.clk, i_D=ClockSignal("rtio"), o_Q=beat2), - ] - - ed1 = DDMTDEdgeDetector(beat1) - ed2 = DDMTDEdgeDetector(beat2) - self.submodules += ed1, ed2 - - counting = Signal() - counter = Signal(N.bit_length()) - result = Signal.like(counter) - self.sync.helper += [ - If(counting, - counter.eq(counter + 1) - ).Else( - result.eq(counter) - ), - - If(ed1.rising, counting.eq(1), counter.eq(0)), - If(ed2.rising, counting.eq(0)) - ] - - bsync = BusSynchronizer(len(result), "helper", "sys") - self.submodules += bsync - self.comb += [ - bsync.i.eq(result), - self.dt.status.eq(bsync.o) - ] - - -# This assumes: -# * fine RTIO frequency (rtiox) = 2*RTIO frequency -# * JESD and coarse RTIO clocks are the same -# (only reset may differ). -class SysrefSampler(Module, AutoCSR): - def __init__(self, sysref_pads, coarse_ts, sysref_phase_bits=8): - self.sh_error = CSRStatus() - self.sh_error_reset = CSRStorage() - # Note: only the lower log2(RTIO frequency / SYSREF frequency) bits are stable - self.sysref_phase = CSRStatus(8) - - self.jref = Signal() - - # # # - - sysref_se = Signal() - sysref_oversample = Signal(4) - self.specials += [ - Instance("IBUFDS", i_I=sysref_pads.p, i_IB=sysref_pads.n, o_O=sysref_se), - Instance("ISERDESE3", - p_IS_CLK_INVERTED=0, - p_IS_CLK_B_INVERTED=1, - p_DATA_WIDTH=4, - - i_D=sysref_se, - i_RST=ResetSignal("rtio"), - i_FIFO_RD_EN=0, - i_CLK=ClockSignal("rtiox"), - i_CLK_B=ClockSignal("rtiox"), # locally inverted - i_CLKDIV=ClockSignal("rtio"), - o_Q=sysref_oversample) - ] - - self.comb += self.jref.eq(sysref_oversample[1]) - sh_error = Signal() - sh_error_reset = Signal() - self.sync.rtio += [ - If(~( (sysref_oversample[0] == sysref_oversample[1]) - & (sysref_oversample[1] == sysref_oversample[2])), - sh_error.eq(1) - ), - If(sh_error_reset, sh_error.eq(0)) - ] - self.specials += [ - MultiReg(self.sh_error_reset.storage, sh_error_reset, "rtio"), - MultiReg(sh_error, self.sh_error.status) - ] - - jref_r = Signal() - sysref_phase_rtio = Signal(sysref_phase_bits) - self.sync.rtio += [ - jref_r.eq(self.jref), - If(self.jref & ~jref_r, sysref_phase_rtio.eq(coarse_ts)) - ] - sysref_phase_rtio.attr.add("no_retiming") - self.specials += MultiReg(sysref_phase_rtio, self.sysref_phase.status) diff --git a/artiq/gateware/rtio/phy/sawg.py b/artiq/gateware/rtio/phy/sawg.py deleted file mode 100644 index 7968eb2b6..000000000 --- a/artiq/gateware/rtio/phy/sawg.py +++ /dev/null @@ -1,39 +0,0 @@ -from collections import namedtuple - -from migen import * -from artiq.gateware.rtio import rtlink - -from artiq.gateware.dsp.sawg import Channel as _Channel - - -_Phy = namedtuple("Phy", "rtlink probes overrides") - -_ChannelPHY = ClockDomainsRenamer("rio_phy")(_Channel) - - -class Channel(_ChannelPHY): - def __init__(self, *args, **kwargs): - _ChannelPHY.__init__(self, *args, **kwargs) - self.phys = [] - cfg = self.i[0] - rl = rtlink.Interface(rtlink.OInterface( - data_width=len(cfg.data), address_width=len(cfg.addr), - enable_replace=False)) - self.comb += [ - cfg.stb.eq(rl.o.stb), - rl.o.busy.eq(~cfg.ack), - cfg.data.eq(rl.o.data), - cfg.addr.eq(rl.o.address), - ] - self.phys.append(_Phy(rl, [], [])) - for i in self.i[1:]: - rl = rtlink.Interface(rtlink.OInterface(len(i.payload), - delay=-i.latency)) - self.comb += [ - i.stb.eq(rl.o.stb), - rl.o.busy.eq(~i.ack), - i.payload.raw_bits().eq(rl.o.data), - ] - # TODO probes, overrides - self.phys.append(_Phy(rl, [], [])) - self.phys_named = dict(zip(self.i_names, self.phys)) diff --git a/artiq/gateware/targets/metlino.py b/artiq/gateware/targets/metlino.py deleted file mode 100755 index ffb2b38b9..000000000 --- a/artiq/gateware/targets/metlino.py +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -from functools import partial - -from migen import * -from migen.build.generic_platform import IOStandard - -from misoc.cores import gpio -from misoc.integration.builder import builder_args, builder_argdict -from misoc.interconnect.csr import * -from misoc.targets.metlino import * - -from artiq.gateware.amp import AMPSoC -from artiq.gateware import eem -from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale -from artiq.gateware.drtio.transceiver import gth_ultrascale -from artiq.gateware.drtio import * -from artiq.build_soc import * - - -def workaround_us_lvds_tristate(platform): - # Those shoddy Kintex Ultrascale FPGAs take almost a microsecond to change the direction of a - # LVDS I/O buffer. The application has to cope with it and this cannot be handled at static - # timing analysis. Disable the latter for IOBUFDS. - # See: - # https://forums.xilinx.com/t5/Timing-Analysis/Delay-890-ns-in-OBUFTDS-in-Kintex-UltraScale/td-p/868364 - platform.add_platform_command( - "set_false_path -through [get_pins -filter {{REF_PIN_NAME == T}} -of [get_cells -filter {{REF_NAME == IOBUFDS}}]]") - - -class Master(MiniSoC, AMPSoC): - mem_map = { - "cri_con": 0x10000000, - "rtio": 0x11000000, - "rtio_dma": 0x12000000, - "drtioaux": 0x14000000, - "mailbox": 0x70000000 - } - mem_map.update(MiniSoC.mem_map) - - def __init__(self, gateware_identifier_str=None, **kwargs): - MiniSoC.__init__(self, - cpu_type="vexriscv", - cpu_bus_width=64, - sdram_controller_type="minicon", - l2_size=128*1024, - integrated_sram_size=8192, - ethmac_nrxslots=4, - ethmac_ntxslots=4, - csr_address_width=15, - **kwargs) - AMPSoC.__init__(self) - add_identifier(self, gateware_identifier_str=gateware_identifier_str) - - platform = self.platform - rtio_clk_freq = 150e6 - - self.comb += platform.request("input_clk_sel").eq(1) - self.comb += platform.request("filtered_clk_sel").eq(1) - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) - self.csr_devices.append("si5324_rst_n") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - - self.submodules.drtio_transceiver = gth_ultrascale.GTH( - clock_pads=platform.request("cdr_clk_clean", 0), - data_pads=[platform.request("mch_fabric_d", i) for i in range(11)], - sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq) - self.csr_devices.append("drtio_transceiver") - - self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) - - drtio_csr_group = [] - drtioaux_csr_group = [] - drtioaux_memory_group = [] - drtio_cri = [] - for i in range(len(self.drtio_transceiver.channels)): - core_name = "drtio" + str(i) - coreaux_name = "drtioaux" + str(i) - memory_name = "drtioaux" + str(i) + "_mem" - drtio_csr_group.append(core_name) - drtioaux_csr_group.append(coreaux_name) - drtioaux_memory_group.append(memory_name) - - cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) - - core = cdr(DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) - setattr(self.submodules, core_name, core) - drtio_cri.append(core.cri) - self.csr_devices.append(core_name) - - coreaux = cdr(DRTIOAuxController(core.link_layer, self.cpu_dw)) - setattr(self.submodules, coreaux_name, coreaux) - self.csr_devices.append(coreaux_name) - - memory_address = self.mem_map["drtioaux"] + 0x800*i - self.add_wb_slave(memory_address, 0x800, - coreaux.bus) - self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) - self.config["HAS_DRTIO"] = None - self.config["HAS_DRTIO_ROUTING"] = None - self.add_csr_group("drtio", drtio_csr_group) - self.add_csr_group("drtioaux", drtioaux_csr_group) - self.add_memory_group("drtioaux_mem", drtioaux_memory_group) - - rtio_clk_period = 1e9/rtio_clk_freq - gth0 = self.drtio_transceiver.gths[0] - platform.add_period_constraint(gth0.txoutclk, rtio_clk_period/2) - platform.add_period_constraint(gth0.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gth0.txoutclk, gth0.rxoutclk) - for gth in self.drtio_transceiver.gths[1:]: - platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, gth0.txoutclk, gth.rxoutclk) - - self.rtio_channels = rtio_channels = [] - for i in range(4): - phy = ttl_simple.Output(platform.request("user_led", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - output_4x = partial(ttl_serdes_ultrascale.Output, 4) - eem.DIO.add_std(self, 2, output_4x, output_4x, - iostandard=lambda eem: IOStandard("LVDS")) - eem.Urukul.add_std(self, 0, 1, output_4x, - iostandard=lambda eem: IOStandard("LVDS")) - eem.Zotino.add_std(self, 3, output_4x, - iostandard=lambda eem: IOStandard("LVDS")) - workaround_us_lvds_tristate(platform) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) - - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) - self.csr_devices.append("rtio_core") - - self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) - self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( - rtio.DMA(self.get_native_sdram_if(), self.cpu_dw)) - self.register_kernel_cpu_csrdevice("rtio") - self.register_kernel_cpu_csrdevice("rtio_dma") - self.submodules.cri_con = rtio.CRIInterconnectShared( - [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri] + drtio_cri, - enable_routing=True) - self.register_kernel_cpu_csrdevice("cri_con") - self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) - self.csr_devices.append("routing_table") - - -def main(): - parser = argparse.ArgumentParser( - description="Metlino gateware and firmware builder") - builder_args(parser) - soc_sdram_args(parser) - parser.set_defaults(output_dir="artiq_metlino") - parser.add_argument("--gateware-identifier-str", default=None, - help="Override ROM identifier") - args = parser.parse_args() - args.variant = "master" - soc = Master(gateware_identifier_str=args.gateware_identifier_str, **soc_sdram_argdict(args)) - build_artiq_soc(soc, builder_argdict(args)) - - -if __name__ == "__main__": - main() diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py deleted file mode 100755 index 527d37b5c..000000000 --- a/artiq/gateware/targets/sayma_amc.py +++ /dev/null @@ -1,462 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import os -import warnings -from functools import partial - -from migen import * -from migen.build.generic_platform import IOStandard - -from misoc.cores import gpio -from misoc.integration.builder import builder_args, builder_argdict -from misoc.interconnect.csr import * -from misoc.targets.sayma_amc import * - -from artiq.gateware.amp import AMPSoC -from artiq.gateware import eem -from artiq.gateware import rtio -from artiq.gateware import jesd204_tools -from artiq.gateware import fmcdio_vhdci_eem -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg -from artiq.gateware.drtio.transceiver import gth_ultrascale -from artiq.gateware.drtio.siphaser import SiPhaser7Series -from artiq.gateware.drtio.wrpll import WRPLL, DDMTDSamplerExtFF -from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import * -from artiq.build_soc import * - - -def workaround_us_lvds_tristate(platform): - # Those shoddy Kintex Ultrascale FPGAs take almost a microsecond to change the direction of a - # LVDS I/O buffer. The application has to cope with it and this cannot be handled at static - # timing analysis. Disable the latter for IOBUFDS. - # See: - # https://forums.xilinx.com/t5/Timing-Analysis/Delay-890-ns-in-OBUFTDS-in-Kintex-UltraScale/td-p/868364 - platform.add_platform_command( - "set_false_path -through [get_pins -filter {{REF_PIN_NAME == T}} -of [get_cells -filter {{REF_NAME == IOBUFDS}}]]") - - -class RTMUARTForward(Module): - def __init__(self, platform): - # forward RTM UART to second FTDI UART channel - serial_1 = platform.request("serial", 1) - serial_rtm = platform.request("serial_rtm") - self.comb += [ - serial_1.tx.eq(serial_rtm.rx), - serial_rtm.tx.eq(serial_1.rx) - ] - - -class SatelliteBase(MiniSoC): - mem_map = { - "drtioaux": 0x14000000, - } - mem_map.update(MiniSoC.mem_map) - - def __init__(self, rtio_clk_freq=125e6, identifier_suffix="", gateware_identifier_str=None, with_sfp=False, *, with_wrpll, **kwargs): - MiniSoC.__init__(self, - cpu_type="vexriscv", - cpu_bus_width=64, - sdram_controller_type="minicon", - l2_size=128*1024, - integrated_sram_size=8192, - ethmac_nrxslots=4, - ethmac_ntxslots=4, - **kwargs) - add_identifier(self, suffix=identifier_suffix, gateware_identifier_str=gateware_identifier_str) - self.rtio_clk_freq = rtio_clk_freq - - platform = self.platform - - if with_wrpll: - clock_recout_pads = platform.request("ddmtd_rec_clk") - else: - clock_recout_pads = None - if with_sfp: - # Use SFP0 to connect to master (Kasli) - self.comb += platform.request("sfp_tx_disable", 0).eq(0) - drtio_uplink = platform.request("sfp", 0) - else: - drtio_uplink = platform.request("fat_pipe", 0) - self.submodules.drtio_transceiver = gth_ultrascale.GTH( - clock_pads=platform.request("cdr_clk_clean"), - data_pads=[drtio_uplink, platform.request("rtm_amc_link")], - sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq, - clock_recout_pads=clock_recout_pads) - self.csr_devices.append("drtio_transceiver") - - self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) - - drtioaux_csr_group = [] - drtioaux_memory_group = [] - drtiorep_csr_group = [] - self.drtio_cri = [] - for i in range(len(self.drtio_transceiver.channels)): - coreaux_name = "drtioaux" + str(i) - memory_name = "drtioaux" + str(i) + "_mem" - drtioaux_csr_group.append(coreaux_name) - drtioaux_memory_group.append(memory_name) - - cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) - - if i == 0: - self.submodules.rx_synchronizer = cdr(XilinxRXSynchronizer()) - core = cdr(DRTIOSatellite( - self.rtio_tsc, self.drtio_transceiver.channels[i], - self.rx_synchronizer)) - self.submodules.drtiosat = core - self.csr_devices.append("drtiosat") - else: - corerep_name = "drtiorep" + str(i-1) - drtiorep_csr_group.append(corerep_name) - - core = cdr(DRTIORepeater( - self.rtio_tsc, self.drtio_transceiver.channels[i])) - setattr(self.submodules, corerep_name, core) - self.drtio_cri.append(core.cri) - self.csr_devices.append(corerep_name) - - coreaux = cdr(DRTIOAuxController(core.link_layer, self.cpu_dw)) - setattr(self.submodules, coreaux_name, coreaux) - self.csr_devices.append(coreaux_name) - - memory_address = self.mem_map["drtioaux"] + 0x800*i - self.add_wb_slave(memory_address, 0x800, - coreaux.bus) - self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) - self.config["HAS_DRTIO"] = None - self.config["HAS_DRTIO_ROUTING"] = None - self.add_csr_group("drtioaux", drtioaux_csr_group) - self.add_memory_group("drtioaux_mem", drtioaux_memory_group) - self.add_csr_group("drtiorep", drtiorep_csr_group) - - rtio_clk_period = 1e9/rtio_clk_freq - self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - if with_wrpll: - self.comb += [ - platform.request("filtered_clk_sel").eq(0), - platform.request("ddmtd_main_dcxo_oe").eq(1), - platform.request("ddmtd_helper_dcxo_oe").eq(1) - ] - self.submodules.wrpll_sampler = DDMTDSamplerExtFF( - platform.request("ddmtd_inputs")) - self.submodules.wrpll = WRPLL( - helper_clk_pads=platform.request("ddmtd_helper_clk"), - main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), - helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), - ddmtd_inputs=self.wrpll_sampler) - self.csr_devices.append("wrpll") - platform.add_period_constraint(self.wrpll.cd_helper.clk, rtio_clk_period*0.99) - platform.add_false_path_constraints(self.crg.cd_sys.clk, self.wrpll.cd_helper.clk) - else: - self.comb += platform.request("filtered_clk_sel").eq(1) - self.submodules.siphaser = SiPhaser7Series( - si5324_clkin=platform.request("si5324_clkin"), - rx_synchronizer=self.rx_synchronizer, - ultrascale=True, - rtio_clk_freq=rtio_clk_freq) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) - self.csr_devices.append("siphaser") - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) - self.csr_devices.append("si5324_rst_n") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - - gth = self.drtio_transceiver.gths[0] - platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2) - platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gth.txoutclk, gth.rxoutclk) - - def add_rtio(self, rtio_channels): - # Only add MonInj core if there is anything to monitor - if any([len(c.probes) for c in rtio_channels]): - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) - self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors) - self.submodules.cri_con = rtio.CRIInterconnectShared( - [self.drtiosat.cri], - [self.local_io.cri] + self.drtio_cri, - mode="sync", enable_routing=True) - self.csr_devices.append("cri_con") - self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) - self.csr_devices.append("routing_table") - - -# JESD204 DAC Channel Group -class JDCGSAWG(Module, AutoCSR): - def __init__(self, platform, sys_crg, jesd_crg, dac): - # Kintex Ultrascale GTH, speed grade -1C: - # CPLL linerate (D=1): 4.0 - 8.5 Gb/s - self.submodules.jesd = jesd204_tools.UltrascaleTX( - platform, sys_crg, jesd_crg, dac) - - self.submodules.sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] - - for conv, ch in zip(self.jesd.core.sink.flatten(), self.sawgs): - assert len(Cat(ch.o)) == len(conv) - self.sync.jesd += conv.eq(Cat(ch.o)) - - -class JDCGPattern(Module, AutoCSR): - def __init__(self, platform, sys_crg, jesd_crg, dac): - self.submodules.jesd = jesd204_tools.UltrascaleTX( - platform, sys_crg, jesd_crg, dac) - - self.sawgs = [] - - ramp = Signal(4) - self.sync.rtio += ramp.eq(ramp + 1) - - samples = [[Signal(16) for i in range(4)] for j in range(4)] - self.comb += [ - a.eq(Cat(b)) for a, b in zip( - self.jesd.core.sink.flatten(), samples) - ] - # ch0: 16-step ramp with big carry toggles - for i in range(4): - self.comb += [ - samples[0][i][-4:].eq(ramp), - samples[0][i][:-4].eq(0x7ff if i % 2 else 0x800) - ] - # ch1: 50 MHz - from math import pi, cos - data = [int(round(cos(i/12*2*pi)*((1 << 15) - 1))) - for i in range(12)] - k = Signal(2) - self.sync.rtio += If(k == 2, k.eq(0)).Else(k.eq(k + 1)) - self.comb += [ - Case(k, { - i: [samples[1][j].eq(data[i*4 + j]) for j in range(4)] - for i in range(3) - }) - ] - # ch2: ch0, ch3: ch1 - self.comb += [ - Cat(samples[2]).eq(Cat(samples[0])), - Cat(samples[3]).eq(Cat(samples[1])) - ] - - -class JDCGSyncDDS(Module, AutoCSR): - def __init__(self, platform, sys_crg, jesd_crg, dac): - self.submodules.jesd = jesd204_tools.UltrascaleTX( - platform, sys_crg, jesd_crg, dac) - self.coarse_ts = Signal(32) - - self.sawgs = [] - - ftw = round(2**len(self.coarse_ts)*9e6/600e6) - parallelism = 4 - - mul_1 = Signal.like(self.coarse_ts) - mul_2 = Signal.like(self.coarse_ts) - mul_3 = Signal.like(self.coarse_ts) - self.sync.rtio += [ - mul_1.eq(self.coarse_ts*ftw*parallelism), - mul_2.eq(mul_1), - mul_3.eq(mul_2) - ] - - phases = [Signal.like(self.coarse_ts) for i in range(parallelism)] - self.sync.rtio += [phases[i].eq(mul_3 + i*ftw) for i in range(parallelism)] - - resolution = 10 - steps = 2**resolution - from math import pi, cos - data = [(2**16 + round(cos(i/steps*2*pi)*((1 << 15) - 1))) & 0xffff - for i in range(steps)] - samples = [Signal(16) for i in range(4)] - for phase, sample in zip(phases, samples): - table = Memory(16, steps, init=data) - table_port = table.get_port(clock_domain="rtio") - self.specials += table, table_port - self.comb += [ - table_port.adr.eq(phase >> (len(self.coarse_ts) - resolution)), - sample.eq(table_port.dat_r) - ] - - self.sync.rtio += [sink.eq(Cat(samples)) - for sink in self.jesd.core.sink.flatten()] - - -class Satellite(SatelliteBase): - """ - DRTIO satellite with local DAC/SAWG channels, as well as TTL channels via FMC and VHDCI carrier. - """ - def __init__(self, jdcg_type, **kwargs): - SatelliteBase.__init__(self, 150e6, - identifier_suffix="." + jdcg_type, - **kwargs) - - platform = self.platform - - self.submodules += RTMUARTForward(platform) - - # RTM bitstream upload - slave_fpga_cfg = self.platform.request("rtm_fpga_cfg") - self.submodules.slave_fpga_cfg = gpio.GPIOTristate([ - slave_fpga_cfg.cclk, - slave_fpga_cfg.din, - slave_fpga_cfg.done, - slave_fpga_cfg.init_b, - slave_fpga_cfg.program_b, - ]) - self.csr_devices.append("slave_fpga_cfg") - self.config["SLAVE_FPGA_GATEWARE"] = 0x200000 - - self.rtio_channels = rtio_channels = [] - for i in range(4): - phy = ttl_simple.Output(platform.request("user_led", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - mcx_io = platform.request("mcx_io", 0) - phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) - self.comb += mcx_io.direction.eq(phy.oe) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - mcx_io = platform.request("mcx_io", 1) - phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) - self.comb += mcx_io.direction.eq(phy.oe) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.submodules.jesd_crg = jesd204_tools.UltrascaleCRG( - platform, use_rtio_clock=True) - cls = { - "sawg": JDCGSAWG, - "pattern": JDCGPattern, - "syncdds": JDCGSyncDDS - }[jdcg_type] - self.submodules.jdcg_0 = cls(platform, self.crg, self.jesd_crg, 0) - self.submodules.jdcg_1 = cls(platform, self.crg, self.jesd_crg, 1) - self.csr_devices.append("jesd_crg") - self.csr_devices.append("jdcg_0") - self.csr_devices.append("jdcg_1") - self.config["HAS_JDCG"] = None - self.add_csr_group("jdcg", ["jdcg_0", "jdcg_1"]) - self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) - rtio_channels.extend(rtio.Channel.from_phy(phy) - for sawg in self.jdcg_0.sawgs + - self.jdcg_1.sawgs - for phy in sawg.phys) - - # FMC-VHDCI-EEM DIOs x 2 (all OUTPUTs) - platform.add_connectors(fmcdio_vhdci_eem.connectors) - output_4x = partial(ttl_serdes_ultrascale.Output, 4) - eem.DIO.add_std(self, 0, - output_4x, output_4x, - iostandard=lambda eem: IOStandard("LVDS")) - eem.DIO.add_std(self, 1, - output_4x, output_4x, - iostandard=lambda eem: IOStandard("LVDS")) - # FMC-DIO-32ch-LVDS-a Direction Control Pins (via shift register) as TTLs x 3 - platform.add_extension(fmcdio_vhdci_eem.io) - print("fmcdio_vhdci_eem.[CLK, SER, LATCH] starting at RTIO channel 0x{:06x}" - .format(len(rtio_channels))) - fmcdio_dirctl = platform.request("fmcdio_dirctl", 0) - fmcdio_dirctl_phys = [ - ttl_simple.Output(fmcdio_dirctl.clk), - ttl_simple.Output(fmcdio_dirctl.ser), - ttl_simple.Output(fmcdio_dirctl.latch) - ] - for phy in fmcdio_dirctl_phys: - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - workaround_us_lvds_tristate(platform) - - self.add_rtio(rtio_channels) - - self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - platform.request("amc_fpga_sysref", 0), self.rtio_tsc.coarse_ts) - self.csr_devices.append("sysref_sampler") - self.jdcg_0.jesd.core.register_jref(self.sysref_sampler.jref) - self.jdcg_1.jesd.core.register_jref(self.sysref_sampler.jref) - if jdcg_type == "syncdds": - self.comb += [ - self.jdcg_0.coarse_ts.eq(self.rtio_tsc.coarse_ts), - self.jdcg_1.coarse_ts.eq(self.rtio_tsc.coarse_ts), - ] - - -class SimpleSatellite(SatelliteBase): - def __init__(self, **kwargs): - SatelliteBase.__init__(self, **kwargs) - - platform = self.platform - - self.submodules += RTMUARTForward(platform) - - rtio_channels = [] - for i in range(4): - phy = ttl_simple.Output(platform.request("user_led", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - mcx_io = platform.request("mcx_io", 0) - phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) - self.comb += mcx_io.direction.eq(phy.oe) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - mcx_io = platform.request("mcx_io", 1) - phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) - self.comb += mcx_io.direction.eq(phy.oe) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.add_rtio(rtio_channels) - - -def main(): - parser = argparse.ArgumentParser( - description="Sayma AMC gateware and firmware builder") - builder_args(parser) - soc_sayma_amc_args(parser) - parser.set_defaults(output_dir="artiq_sayma") - parser.add_argument("-V", "--variant", default="satellite", - help="variant: satellite/simplesatellite " - "(default: %(default)s)") - parser.add_argument("--sfp", default=False, action="store_true", - help="use SFP port for DRTIO instead of uTCA backplane") - parser.add_argument("--rtm-csr-csv", - default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"), - help="CSV file listing remote CSRs on RTM (default: %(default)s)") - parser.add_argument("--jdcg-type", - default="sawg", - help="Change type of signal generator. This is used exclusively for " - "development and debugging.") - parser.add_argument("--with-wrpll", default=False, action="store_true") - parser.add_argument("--gateware-identifier-str", default=None, - help="Override ROM identifier") - args = parser.parse_args() - - variant = args.variant.lower() - if variant == "satellite": - soc = Satellite( - with_sfp=args.sfp, - jdcg_type=args.jdcg_type, - with_wrpll=args.with_wrpll, - gateware_identifier_str=args.gateware_identifier_str, - **soc_sayma_amc_argdict(args)) - elif variant == "simplesatellite": - soc = SimpleSatellite( - with_sfp=args.sfp, - with_wrpll=args.with_wrpll, - gateware_identifier_str=args.gateware_identifier_str, - **soc_sayma_amc_argdict(args)) - else: - raise SystemExit("Invalid variant (-V/--variant)") - - build_artiq_soc(soc, builder_argdict(args)) - - -if __name__ == "__main__": - main() diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py deleted file mode 100755 index 9d8a818b4..000000000 --- a/artiq/gateware/targets/sayma_rtm.py +++ /dev/null @@ -1,280 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import os -import subprocess -import struct - -from migen import * -from migen.genlib.cdc import MultiReg - -from misoc.interconnect.csr import * -from misoc.cores import gpio -from misoc.cores import spi2 -from misoc.cores.a7_gtp import * -from misoc.targets.sayma_rtm import BaseSoC, soc_sayma_rtm_args, soc_sayma_rtm_argdict -from misoc.integration.builder import Builder, builder_args, builder_argdict - -from artiq.gateware import rtio -from artiq.gateware import jesd204_tools -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series -from artiq.gateware.rtio.xilinx_clocking import RTIOClockMultiplier, fix_serdes_timing_path -from artiq.gateware.drtio.transceiver import gtp_7series -from artiq.gateware.drtio.siphaser import SiPhaser7Series -from artiq.gateware.drtio.wrpll import WRPLL, DDMTDSamplerGTP -from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import * -from artiq.build_soc import add_identifier -from artiq import __artiq_dir__ as artiq_dir - - -class _SatelliteBase(BaseSoC): - mem_map = { - "drtioaux": 0x50000000, - } - mem_map.update(BaseSoC.mem_map) - - def __init__(self, rtio_clk_freq, *, with_wrpll, gateware_identifier_str, **kwargs): - BaseSoC.__init__(self, - cpu_type="vexriscv", - cpu_bus_width=64, - **kwargs) - add_identifier(self, gateware_identifier_str=gateware_identifier_str) - self.rtio_clk_freq = rtio_clk_freq - - platform = self.platform - - disable_cdrclkc_ibuf = Signal(reset=1) - disable_cdrclkc_ibuf.attr.add("no_retiming") - cdrclkc_clkout = platform.request("cdr_clk_clean") - cdrclkc_clkout_buf = Signal() - self.specials += Instance("IBUFDS_GTE2", - i_CEB=disable_cdrclkc_ibuf, - i_I=cdrclkc_clkout.p, i_IB=cdrclkc_clkout.n, - o_O=cdrclkc_clkout_buf) - qpll_drtio_settings = QPLLSettings( - refclksel=0b001, - fbdiv=4, - fbdiv_45=5, - refclk_div=1) - qpll = QPLL(cdrclkc_clkout_buf, qpll_drtio_settings) - self.submodules += qpll - - self.submodules.drtio_transceiver = gtp_7series.GTP( - qpll_channel=qpll.channels[0], - data_pads=[platform.request("rtm_amc_link", 0)], - sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq) - self.csr_devices.append("drtio_transceiver") - self.sync += disable_cdrclkc_ibuf.eq( - ~self.drtio_transceiver.stable_clkin.storage) - - self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) - - cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) - - self.submodules.rx_synchronizer = cdr(XilinxRXSynchronizer()) - core = cdr(DRTIOSatellite( - self.rtio_tsc, self.drtio_transceiver.channels[0], - self.rx_synchronizer)) - self.submodules.drtiosat = core - self.csr_devices.append("drtiosat") - - coreaux = cdr(DRTIOAuxController(core.link_layer, self.cpu_dw)) - self.submodules.drtioaux0 = coreaux - self.csr_devices.append("drtioaux0") - - memory_address = self.mem_map["drtioaux"] - self.add_wb_slave(memory_address, 0x800, - coreaux.bus) - self.add_memory_region("drtioaux0_mem", memory_address | self.shadow_base, 0x800) - - self.config["HAS_DRTIO"] = None - self.add_csr_group("drtioaux", ["drtioaux0"]) - self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) - - gtp = self.drtio_transceiver.gtps[0] - rtio_clk_period = 1e9/rtio_clk_freq - self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - if with_wrpll: - self.comb += [ - platform.request("filtered_clk_sel").eq(0), - platform.request("ddmtd_main_dcxo_oe").eq(1), - platform.request("ddmtd_helper_dcxo_oe").eq(1) - ] - self.submodules.wrpll_sampler = DDMTDSamplerGTP( - self.drtio_transceiver, - platform.request("cdr_clk_clean_fabric")) - self.submodules.wrpll = WRPLL( - helper_clk_pads=platform.request("ddmtd_helper_clk"), - main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), - helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), - ddmtd_inputs=self.wrpll_sampler) - self.csr_devices.append("wrpll") - platform.add_period_constraint(self.wrpll.cd_helper.clk, rtio_clk_period*0.99) - platform.add_false_path_constraints(self.crg.cd_sys.clk, self.wrpll.cd_helper.clk) - platform.add_false_path_constraints(self.wrpll.cd_helper.clk, gtp.rxoutclk) - else: - self.comb += platform.request("filtered_clk_sel").eq(1) - self.submodules.siphaser = SiPhaser7Series( - si5324_clkin=platform.request("si5324_clkin"), - rx_synchronizer=self.rx_synchronizer, - ref_clk=self.crg.cd_sys.clk, ref_div2=True, - rtio_clk_freq=rtio_clk_freq) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) - self.csr_devices.append("siphaser") - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) - self.csr_devices.append("si5324_rst_n") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - - platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) - platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gtp.txoutclk, gtp.rxoutclk) - - self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq) - self.csr_devices.append("rtio_crg") - fix_serdes_timing_path(platform) - - def add_rtio(self, rtio_channels): - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) - self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors) - self.comb += self.drtiosat.cri.connect(self.local_io.cri) - - -class Satellite(_SatelliteBase): - def __init__(self, **kwargs): - _SatelliteBase.__init__(self, **kwargs) - - platform = self.platform - - rtio_channels = [] - for bm in range(2): - print("BaseMod{} RF switches starting at RTIO channel 0x{:06x}" - .format(bm, len(rtio_channels))) - for i in range(4): - phy = ttl_serdes_7series.Output_8X(platform.request("basemod{}_rfsw".format(bm), i), - invert=True) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - print("BaseMod{} attenuator starting at RTIO channel 0x{:06x}" - .format(bm, len(rtio_channels))) - basemod_att = platform.request("basemod{}_att".format(bm)) - for name in "rst_n clk le".split(): - signal = getattr(basemod_att, name) - for i in range(len(signal)): - phy = ttl_simple.Output(signal[i]) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = ttl_simple.Output(basemod_att.mosi[0]) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - for i in range(3): - self.comb += basemod_att.mosi[i+1].eq(basemod_att.miso[i]) - phy = ttl_simple.InOut(basemod_att.miso[3]) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.add_rtio(rtio_channels) - - self.comb += platform.request("clk_src_ext_sel").eq(0) - - # HMC clock chip and DAC control - self.comb += [ - platform.request("ad9154_rst_n", 0).eq(1), - platform.request("ad9154_rst_n", 1).eq(1) - ] - self.submodules.converter_spi = spi2.SPIMaster(spi2.SPIInterface( - platform.request("hmc_spi"), - platform.request("ad9154_spi", 0), - platform.request("ad9154_spi", 1))) - self.csr_devices.append("converter_spi") - self.submodules.hmc7043_reset = gpio.GPIOOut( - platform.request("hmc7043_reset"), reset_out=1) - self.csr_devices.append("hmc7043_reset") - self.submodules.hmc7043_gpo = gpio.GPIOIn( - platform.request("hmc7043_gpo")) - self.csr_devices.append("hmc7043_gpo") - self.config["HAS_HMC830_7043"] = None - self.config["HAS_AD9154"] = None - self.config["AD9154_COUNT"] = 2 - self.config["CONVERTER_SPI_HMC830_CS"] = 0 - self.config["CONVERTER_SPI_HMC7043_CS"] = 1 - self.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 - self.config["HMC830_REF"] = str(int(self.rtio_clk_freq/1e6)) - - # HMC workarounds - self.comb += platform.request("hmc830_pwr_en").eq(1) - self.submodules.hmc7043_out_en = gpio.GPIOOut( - platform.request("hmc7043_out_en")) - self.csr_devices.append("hmc7043_out_en") - - # DDMTD - sysref_pads = platform.request("rtm_fpga_sysref", 0) - self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(sysref_pads, self.rtio_clk_freq) - self.csr_devices.append("sysref_ddmtd") - platform.add_false_path_constraints( - self.sysref_ddmtd.cd_helper.clk, self.drtio_transceiver.gtps[0].txoutclk) - platform.add_false_path_constraints( - self.sysref_ddmtd.cd_helper.clk, self.crg.cd_sys.clk) - - -class SatmanSoCBuilder(Builder): - def __init__(self, *args, **kwargs): - Builder.__init__(self, *args, **kwargs) - firmware_dir = os.path.join(artiq_dir, "firmware") - self.software_packages = [] - self.add_software_package("satman", os.path.join(firmware_dir, "satman")) - - def initialize_memory(self): - satman = os.path.join(self.output_dir, "software", "satman", - "satman.bin") - with open(satman, "rb") as boot_file: - boot_data = [] - unpack_endian = " l1: - lim = l1 - clip = 2 - with self.subTest(i0=i0, i1=i1): - self.assertEqual(lim, o) - self.assertEqual(clip, c) - yield - - mg.run_simulation(self.dut, (gen(), rec())) - - def test_inst(self): - pass - - def test_run(self): - self._sweep() - - def test_limits(self): - for l0 in -8, 0, 1, 7: - for l1 in -8, 0, 1, 7: - self.setUp() - self.dut.l0.reset = l0 - self.dut.l1.reset = l1 - with self.subTest(l0=l0, l1=l1): - self._sweep() diff --git a/artiq/gateware/test/dsp/test_sawg.py b/artiq/gateware/test/dsp/test_sawg.py deleted file mode 100644 index fd392607d..000000000 --- a/artiq/gateware/test/dsp/test_sawg.py +++ /dev/null @@ -1,36 +0,0 @@ -import numpy as np - -from migen import * -from migen.fhdl.verilog import convert - -from artiq.gateware.dsp import sawg -from artiq.gateware.test.dsp.tools import xfer - - -def _test_gen_dds(dut, o): - yield from xfer(dut, - a=dict(a0=10), - p=dict(a0=0), - f=dict(a0=1), - ) - for i in range(256//dut.parallelism): - yield - o.append((yield from [(yield _) for _ in dut.xo])) - - -def _test_channel(): - widths = sawg._Widths(t=8, a=4*8, p=8, f=16) - orders = sawg._Orders(a=4, p=1, f=2) - dut = sawg.SplineParallelDDS(widths, orders, parallelism=2) - - if False: - print(convert(dut)) - else: - o = [] - run_simulation(dut, _test_gen_dds(dut, o), vcd_name="dds.vcd") - o = np.array(o) - print(o[:, :]) - - -if __name__ == "__main__": - _test_channel() diff --git a/artiq/gateware/test/dsp/test_sawg_fe.py b/artiq/gateware/test/dsp/test_sawg_fe.py deleted file mode 100644 index 1f7cdc08c..000000000 --- a/artiq/gateware/test/dsp/test_sawg_fe.py +++ /dev/null @@ -1,255 +0,0 @@ -import unittest - -import migen as mg -from numpy import int32 - -from artiq.coredevice import sawg, spline -from artiq.language import (at_mu, now_mu, delay, - core as core_language) -from artiq.gateware.rtio.phy.sawg import Channel -from artiq.sim import devices as sim_devices, time as sim_time - - -class RTIOManager: - def __init__(self): - self.outputs = [] - - def rtio_output(self, target, data): - channel = target >> 8 - addr = target & 0xff - self.outputs.append((now_mu(), channel, addr, data)) - - def rtio_output_wide(self, *args, **kwargs): - self.rtio_output(*args, **kwargs) - - def delay_mu(self, t): - delay(t) - - def patch(self, mod): - assert not hasattr(mod, "_saved") - mod._saved = {} - for name in "rtio_output rtio_output_wide delay_mu".split(): - mod._saved[name] = getattr(mod, name, None) - setattr(mod, name, getattr(self, name)) - - def unpatch(self, mod): - mod.__dict__.update(mod._saved) - del mod._saved - - -class SAWGTest(unittest.TestCase): - def setUp(self): - core_language.set_time_manager(sim_time.Manager()) - self.rtio_manager = RTIOManager() - self.rtio_manager.patch(spline) - self.rtio_manager.patch(sawg) - self.core = sim_devices.Core({}) - self.core.coarse_ref_period = 20/3 - self.core.ref_multiplier = 1 - self.t = self.core.coarse_ref_period - self.channel = mg.ClockDomainsRenamer({"rio_phy": "sys"})( - Channel(width=16, parallelism=2)) - self.driver = sawg.SAWG({"core": self.core}, channel_base=0, - parallelism=self.channel.parallelism) - - def tearDown(self): - self.rtio_manager.unpatch(spline) - self.rtio_manager.unpatch(sawg) - - def test_instantiate(self): - pass - - def test_make_events(self): - d = self.driver - d.offset.set(.9) - delay(2*self.t) - d.frequency0.set(.1) - d.frequency1.set(.1) - delay(2*self.t) - d.offset.set(0) - v = int(round((1 << 48) * .1 * self.t)) - self.assertEqual( - self.rtio_manager.outputs, [ - (0., 1, 0, int(round(self.driver.offset.scale*.9))), - (2.*self.t, 8, 0, int(round( - (1 << self.driver.frequency0.width) * - self.t/self.channel.parallelism*.1))), - (2.*self.t, 3, 0, [int32(v), int32(v >> 32)]), - (4.*self.t, 1, 0, 0), - ]) - - def run_channel(self, events): - def gen(dut, events): - c = 0 - for time, channel, address, data in events: - time //= self.t - assert c <= time - while c < time: - yield - c += 1 - for phy in dut.phys: - yield phy.rtlink.o.stb.eq(0) - rt = dut.phys[channel].rtlink.o - if isinstance(data, list): - data = sum(int(d) << (i*32) for i, d in enumerate(data)) - yield rt.data.eq(int(data)) - if hasattr(rt, "address"): - yield rt.address.eq(address) - yield rt.stb.eq(1) - assert not (yield rt.busy) - # print("{}: set ch {} to {}".format(time, channel, hex(data))) - - def log(dut, data, n): - for i in range(n + dut.latency): - yield - data.append((yield from [(yield _) for _ in dut.o])) - - data = [] - # print(int(events[-1][0]) + 1) - mg.run_simulation(self.channel, [ - gen(self.channel, events), - log(self.channel, data, int(events[-1][0]//self.t) + 1)], - vcd_name="dds.vcd") - return data - - def test_run_channel(self): - self.test_make_events() - self.run_channel(self.rtio_manager.outputs) - - def test_coeff(self): - import struct - # these get discrete_compensate - # [.1, .01, -.00001], [.1, .01, .00001, -.000000001] - for v in [-.1], [.1, -.01]: - ch = self.driver.offset - p = ch.coeff_as_packed(v) - t = ch.time_width - w = ch.width - p = [_ & 0xffffffff for _ in p] - p0 = [int(round(vi*ch.scale*ch.time_scale**i)) - for i, vi in enumerate(v)] - p0 = [struct.pack("<" + "_bhiiqqqq"[(w + i*t)//8], vi - )[:(w + i*t)//8] - for i, vi in enumerate(p0)] - p0 = b"".join(p0) - if len(p0) % 4: - p0 += b"\x00"*(4 - len(p0) % 4) - p0 = list(struct.unpack("<" + "I"*((len(p0) + 3)//4), p0)) - with self.subTest(v): - self.assertEqual(p, p0) - - def test_linear(self): - d = self.driver - d.offset.set_coeff_mu([100, 10]) - delay(10*self.t) - d.offset.set_coeff([0]) - delay(1*self.t) - out = self.run_channel(self.rtio_manager.outputs) - out = out[self.channel.latency + self.channel.u.latency:][:11] - for i in range(len(out) - 1): - with self.subTest(i): - v = 100 + i*10 - self.assertEqual(out[i], [v, v]) - self.assertEqual(out[-1], [0, 0]) - - def test_pack(self): - ch = self.driver.offset - self.assertEqual(ch.coeff_as_packed_mu([1]), [1]) - self.assertEqual(ch.coeff_as_packed_mu([1, 1 << 16]), [1, 1]) - self.assertEqual(ch.coeff_as_packed_mu([1, 1 << 32]), [1, 0]) - self.assertEqual(ch.coeff_as_packed_mu([0x1234, 0xa5a5a5a5]), - [0xa5a51234, 0xa5a5]) - self.assertEqual(ch.coeff_as_packed_mu([1, 2, 3, 4]), - [0x20001, 0x30000, 0, 4, 0]) - self.assertEqual(ch.coeff_as_packed_mu([-1, -2, -3, -4]), - [0xfffeffff, 0xfffdffff, -1, -4, -1]) - self.assertEqual(ch.coeff_as_packed_mu([0, -1, 0, -1]), - [0xffff0000, 0x0000ffff, 0, -1, -1]) - - def test_smooth_linear(self): - ch = self.driver.offset - ch.smooth(.1, .2, 13*self.t, 1) - ch.set(.2) - delay(1*self.t) - out = self.run_channel(self.rtio_manager.outputs) - out = out[self.channel.latency + self.channel.u.latency:][:14] - a = int(round(.1*ch.scale)) - da = int(round(.1*ch.scale*(1 << ch.width)//13)) - for i in range(len(out) - 1): - with self.subTest(i): - v = a + (i*da >> ch.width) - self.assertEqual(out[i], [v, v]) - a = int(round(.2*ch.scale)) - self.assertEqual(out[-1], [a, a]) - - def test_smooth_cubic(self): - ch = self.driver.offset - ch.smooth(.1, .2, 13*self.t, 3) - ch.set(.2) - delay(1*self.t) - out = self.run_channel(self.rtio_manager.outputs) - out = out[self.channel.latency + self.channel.u.latency:][:14] - if False: - import matplotlib.pyplot as plt - plt.plot(sum(out, [])) - plt.show() - - @unittest.skip("needs artiq.sim.time.TimeManager tweak for " - "reverse timeline jumps") - def test_demo_2tone(self): - MHz = 1e-3 - ns = 1. - self.sawg0 = self.driver - - t_up = t_hold = t_down = 400*ns - a1 = .3 - a2 = .4 - order = 3 - - self.sawg0.frequency0.set(10*MHz) - self.sawg0.phase0.set(0.) - self.sawg0.frequency1.set(1*MHz) - self.sawg0.phase1.set(0.) - self.sawg0.frequency2.set(13*MHz) - self.sawg0.phase2.set(0.) - t = now_mu() - self.sawg0.amplitude1.smooth(.0, a1, t_up, order) - at_mu(t) - self.sawg0.amplitude2.smooth(.0, a2, t_up, order) - self.sawg0.amplitude1.set(a1) - self.sawg0.amplitude2.set(a2) - delay(t_hold) - t = now_mu() - self.sawg0.amplitude1.smooth(a1, .0, t_down, order) - at_mu(t) - self.sawg0.amplitude2.smooth(a2, .0, t_down, order) - self.sawg0.amplitude1.set(.0) - self.sawg0.amplitude2.set(.0) - - out = self.run_channel(self.rtio_manager.outputs) - out = sum(out, []) - if True: - import matplotlib.pyplot as plt - plt.plot(out) - plt.show() - - def test_fir_overflow(self): - MHz = 1e-3 - ns = 1. - f1 = self.driver.frequency1 - a1 = self.driver.amplitude1 - p1 = self.driver.phase1 - cfg = self.driver.config - f1.set(1*MHz) - a1.set(.99) - delay(100*ns) - p1.set(.5) - delay(100*ns) - a1.set(0) - - out = self.run_channel(self.rtio_manager.outputs) - out = sum(out, []) - if False: - import matplotlib.pyplot as plt - plt.plot(out) - plt.show() diff --git a/artiq/gateware/test/dsp/test_sawg_phy.py b/artiq/gateware/test/dsp/test_sawg_phy.py deleted file mode 100644 index 35666a5f6..000000000 --- a/artiq/gateware/test/dsp/test_sawg_phy.py +++ /dev/null @@ -1,70 +0,0 @@ -import numpy as np -from operator import or_ - -from migen import * -from migen.fhdl.verilog import convert - -from artiq.gateware.rtio.phy.sawg import Channel -from .tools import rtio_xfer - - -def pack_tri(port, *v): - r = 0 - w = 0 - for vi, p in zip(v, port.payload.flatten()): - w += len(p) - r |= int(vi*(1 << w)) - return r - - -def gen_rtio(dut): - yield - yield from rtio_xfer( - dut, - a1=pack_tri(dut.a1.a, .1), - f0=pack_tri(dut.b.f, .01234567), - f1=pack_tri(dut.a1.f, .01234567), - a2=pack_tri(dut.a1.a, .05), - f2=pack_tri(dut.a1.f, .00534567), - ) - - -def gen_log(dut, o, n): - for i in range(3 + dut.latency): - yield - for i in range(n): - yield - o.append((yield from [(yield _) for _ in dut.o])) - #o.append([(yield dut.a1.xo[0])]) - - -def _test_channel(): - width = 16 - - dut = ClockDomainsRenamer({"rio_phy": "sys"})( - Channel(width=width, parallelism=4) - ) - - if False: - print(convert(dut)) - return - - o = [] - run_simulation( - dut, - [gen_rtio(dut), gen_log(dut, o, 128)], - vcd_name="dds.vcd") - o = np.array(o)/(1 << (width - 1)) - o = o.ravel() - np.savez_compressed("dds.npz", o=o) - - import matplotlib.pyplot as plt - fig, ax = plt.subplots(2) - ax[0].step(np.arange(o.size), o) - ax[1].psd(o, 1 << 10, Fs=1, noverlap=1 << 9, scale_by_freq=False) - fig.savefig("dds.pdf") - plt.show() - - -if __name__ == "__main__": - _test_channel() diff --git a/artiq/gateware/test/dsp/test_spline.py b/artiq/gateware/test/dsp/test_spline.py deleted file mode 100644 index fe2d82c28..000000000 --- a/artiq/gateware/test/dsp/test_spline.py +++ /dev/null @@ -1,31 +0,0 @@ -import numpy as np - -from migen import * -from migen.fhdl.verilog import convert - -from artiq.gateware.dsp.spline import Spline -from .tools import xfer - - -def _test_gen_spline(dut, o): - yield dut.o.ack.eq(1) - yield from xfer(dut, i=dict(a0=0, a1=1, a2=2)) - for i in range(20): - yield - o.append((yield dut.o.a0)) - - -def _test_spline(): - dut = Spline(order=3, width=16, step=1) - - if False: - print(convert(dut)) - else: - o = [] - run_simulation(dut, _test_gen_spline(dut, o), vcd_name="spline.vcd") - o = np.array(o) - print(o) - - -if __name__ == "__main__": - _test_spline() diff --git a/artiq/gateware/test/dsp/tools.py b/artiq/gateware/test/dsp/tools.py deleted file mode 100644 index 8d22ad475..000000000 --- a/artiq/gateware/test/dsp/tools.py +++ /dev/null @@ -1,49 +0,0 @@ -def set_dict(e, **k): - for k, v in k.items(): - if isinstance(v, dict): - yield from set_dict(getattr(e, k), **v) - else: - yield getattr(e, k).eq(v) - - -def xfer(dut, **kw): - ep = [] - for e, v in kw.items(): - e = getattr(dut, e) - yield from set_dict(e, **v) - ep.append(e) - for e in ep: - yield e.stb.eq(1) - while ep: - yield - for e in ep[:]: - if hasattr(e, "busy") and (yield e.busy): - raise ValueError(e, "busy") - if not hasattr(e, "ack") or (yield e.ack): - yield e.stb.eq(0) - ep.remove(e) - - -def szip(*iters): - active = {it: None for it in iters} - while active: - for it in list(active): - while True: - try: - val = it.send(active[it]) - except StopIteration: - del active[it] - break - if val is None: - break - else: - active[it] = (yield val) - val = (yield None) - for it in active: - active[it] = val - - -def rtio_xfer(dut, **kwargs): - yield from szip(*( - xfer(dut.phys_named[k].rtlink, o={"data": v}) - for k, v in kwargs.items())) diff --git a/artiq/test/test_coefficients.py b/artiq/test/test_coefficients.py deleted file mode 100644 index 138e0a86a..000000000 --- a/artiq/test/test_coefficients.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (C) 2014, 2015 Robert Jordens - -import unittest - -import numpy as np - -from artiq.wavesynth import coefficients, compute_samples - - -class TestSplineCoef(unittest.TestCase): - def setUp(self): - self.x = np.arange(5.) - self.y = np.sin(2*np.pi*self.x/5) + np.arange(2)[:, None] - self.s = coefficients.SplineSource(self.x, self.y, order=4) - - def test_get_segment(self): - return list(self.s.get_segment(start=1.5, stop=3.2, scale=.01)) - - def test_synth(self): - d = self.test_get_segment() - d[0]["trigger"] = True - return compute_samples.Synthesizer(self.y.shape[0], [d, d + d]) - - def drive(self, s): - y = [] - for f in 0, 1, None, 0: - if f is not None: - s.select(f) - y += s.trigger()[0] - return y - - def test_run(self): - return self.drive(self.test_synth()) - - def test_compare(self): - scale = 100 - d = list(self.s.get_segment(start=0, stop=4, scale=1/scale)) - d[0]["trigger"] = True - s = compute_samples.Synthesizer(self.y.shape[0], [d]) - s.select(0) - y = s.trigger()[0] - np.testing.assert_almost_equal(y[::scale], self.y[0, :-1]) - - @unittest.skip("manual/visual test") - def test_plot(self): - import matplotlib.pyplot as plt - y = self.test_run() - plt.step(np.arange(len(y)), y) - plt.show() diff --git a/artiq/test/test_wavesynth.py b/artiq/test/test_wavesynth.py deleted file mode 100644 index c8323ba5b..000000000 --- a/artiq/test/test_wavesynth.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright (C) 2014, 2015 Robert Jordens - -import unittest - -from artiq.wavesynth import compute_samples - - -class TestSynthesizer(unittest.TestCase): - program = [ - [ - # frame 0 - { - # frame 0, segment 0, line 0 - "dac_divider": 1, - "duration": 100, - "channel_data": [ - { - # channel 0 - "dds": {"amplitude": [0.0, 0.0, 0.01], - "phase": [0.0, 0.0, 0.0005], - "clear": False} - } - ], - "trigger": True - }, - { - # frame 0, segment 0, line 1 - "dac_divider": 1, - "duration": 100, - "channel_data": [ - { - # channel 0 - "dds": {"amplitude": [49.5, 1.0, -0.01], - "phase": [0.0, 0.05, 0.0005], - "clear": False} - } - ], - "trigger": False - }, - ], - [ - # frame 1 - { - # frame 1, segment 0, line 0 - "dac_divider": 1, - "duration": 100, - "channel_data": [ - { - # channel 0 - "dds": {"amplitude": [100.0, 0.0, -0.01], - "phase": [0.0, 0.1, -0.0005], - "clear": False} - } - ], - "trigger": True - }, - { - # frame 1, segment 0, line 1 - "dac_divider": 1, - "duration": 100, - "channel_data": [ - { - # channel 0 - "dds": {"amplitude": [50.5, -1.0, 0.01], - "phase": [0.0, 0.05, -0.0005], - "clear": False} - } - ], - "trigger": False - } - ], - [ - # frame 2 - { - # frame 2, segment 0, line 0 - "dac_divider": 1, - "duration": 84, - "channel_data": [ - { - # channel 0 - "dds": {"amplitude": [100.0], - "phase": [0.0, 0.05], - "clear": False} - } - ], - "trigger": True - }, - { - # frame 2, segment 1, line 0 - "dac_divider": 1, - "duration": 116, - "channel_data": [ - { - # channel 0 - "dds": {"amplitude": [100.0], - "phase": [0.0, 0.05], - "clear": True} - } - ], - "trigger": True - } - ] - ] - - def setUp(self): - self.dev = compute_samples.Synthesizer(1, self.program) - self.t = list(range(600)) - - def drive(self): - s = self.dev - y = [] - for f in 0, 2, None, 1: - if f is not None: - s.select(f) - y += s.trigger()[0] - x = list(range(600)) - return x, y - - def test_run(self): - x, y = self.drive() - - @unittest.skip("manual/visual test") - def test_plot(self): - from matplotlib import pyplot as plt - x, y = self.drive() - plt.plot(x, y) - plt.show() diff --git a/artiq/wavesynth/__init__.py b/artiq/wavesynth/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/artiq/wavesynth/coefficients.py b/artiq/wavesynth/coefficients.py deleted file mode 100644 index e70a4080e..000000000 --- a/artiq/wavesynth/coefficients.py +++ /dev/null @@ -1,234 +0,0 @@ -# Copyright (C) 2014, 2015 Robert Jordens - -import numpy as np -from scipy.interpolate import splrep, splev, spalde - - -class UnivariateMultiSpline: - """Multidimensional wrapper around `scipy.interpolate.sp*` functions. - `scipy.inteprolate.splprep` is limited to 12 dimensions. - """ - def __init__(self, x, y, *, x0=None, order=4, **kwargs): - self.order = order - self.x = x - self.s = [] - for i, yi in enumerate(y): - if x0 is not None: - yi = self.upsample_knots(x0[i], yi, x) - self.s.append(splrep(x, yi, k=order - 1, **kwargs)) - - def upsample_knots(self, x0, y0, x): - return splev(x, splrep(x0, y0, k=self.order - 1)) - - def lev(self, x, *a, **k): - return np.array([splev(x, si) for si in self.s]) - - def alde(self, x): - u = np.array([spalde(x, si) for si in self.s]) - if len(x) == 1: - u = u[:, None, :] - return u - - def __call__(self, x, use_alde=True): - if use_alde: - u = self.alde(x)[:, :, :self.order] - s = (len(self.s), len(x), self.order) - assert u.shape == s, (u.shape, s) - return u.transpose(2, 0, 1) - else: - return np.array([self.lev(x, der=i) for i in range(self.order)]) - - -def pad_const(x, n, axis=0): - """Prefix and postfix the array `x` by `n` repetitions of the first and - last value along `axis`. - """ - a = np.repeat(x.take([0], axis), n, axis) - b = np.repeat(x.take([-1], axis), n, axis) - xp = np.concatenate([a, x, b], axis) - s = list(x.shape) - s[axis] += 2*n - assert xp.shape == tuple(s), (x.shape, s, xp.shape) - return xp - - -def build_segment(durations, coefficients, target="bias", - variable="amplitude", compress=True): - """Build a wavesynth-style segment from homogeneous duration and - coefficient data. - - :param durations: 1D sequence of line durations. - :param coefficients: 3D array with shape `(n, m, len(durations))`, - with `n` being the interpolation order + 1 and `m` the number of - channels. - :param target: The target component of the channel to affect. - :param variable: The variable within the target component. - :param compress: If `True`, skip zero high order coefficients. - """ - for dxi, yi in zip(durations, coefficients.transpose()): - cd = [] - for yij in yi: - cdj = [] - for yijk in reversed(yij): - if cdj or abs(yijk) or not compress: - cdj.append(float(yijk)) - cdj.reverse() - if not cdj: - cdj.append(float(yij[0])) - cd.append({target: {variable: cdj}}) - yield {"duration": int(dxi), "channel_data": cd} - - -class CoefficientSource: - def crop_x(self, start, stop, num=2): - """Return an array of valid sample positions. - - This method needs to be overloaded if this `CoefficientSource` - does not support sampling at arbitrary positions or at arbitrary - density. - - :param start: First sample position. - :param stop: Last sample position. - :param num: Number of samples between `start` and `stop`. - :return: Array of sample positions. `start` and `stop` should be - returned as the first and last value in the array respectively. - """ - return np.linspace(start, stop, num) - - def scale_x(self, x, scale): - # TODO: This could be moved to the the Driver/Mediator code as it is - # device-specific. - """Scale and round sample positions. - - The sample times may need to be changed and/or decimated if - incompatible with hardware requirements. - - :param x: Input sample positions in data space. - :param scale: Data space position to cycles conversion scale, - in units of x-units per clock cycle. - :return: `x_sample`, the rounded sample positions and `durations`, the - integer durations of the individual samples in cycles. - """ - t = np.rint(x/scale) - x_sample = t*scale - durations = np.diff(t).astype(int) - return x_sample, durations - - def __call__(self, x, **kwargs): - """Perform sampling and return coefficients. - - :param x: Sample positions. - :return: `y` the array of coefficients. `y.shape == (order, n, len(x))` - with `n` being the number of channels.""" - raise NotImplementedError - - def get_segment(self, start, stop, scale, *, cutoff=1e-12, - target="bias", variable="amplitude"): - """Build wavesynth segment. - - :param start: see `crop_x()`. - :param stop: see `crop_x()`. - :param scale: see `scale_x()`. - :param cutoff: coefficient cutoff towards zero to compress data. - """ - x = self.crop_x(start, stop) - x_sample, durations = self.scale_x(x, scale) - coefficients = self(x_sample) - if len(x_sample) == 1 and start == stop: - coefficients = coefficients[:1] - # rescale coefficients accordingly - coefficients *= (scale*np.sign(durations))**np.arange( - coefficients.shape[0])[:, None, None] - if cutoff: - coefficients[np.fabs(coefficients) < cutoff] = 0 - return build_segment(np.fabs(durations), coefficients, target=target, - variable=variable) - - def extend_segment(self, segment, *args, **kwargs): - """Extend a wavesynth segment. - - See `get_segment()` for arguments. - """ - for line in self.get_segment(*args, **kwargs): - segment.add_line(**line) - - -class SplineSource(CoefficientSource): - def __init__(self, x, y, order=4, pad_dx=1.): - """ - :param x: 1D sample positions. - :param y: 2D sample values. - """ - self.x = np.asanyarray(x) - assert self.x.ndim == 1 - self.y = np.asanyarray(y) - assert self.y.ndim == 2 - - if pad_dx is not None: - a = np.arange(-order, 0)*pad_dx + self.x[0] - b = self.x[-1] + np.arange(1, order + 1)*pad_dx - self.x = np.r_[a, self.x, b] - self.y = pad_const(self.y, order, axis=1) - - assert self.y.shape[1] == self.x.shape[0] - self.spline = UnivariateMultiSpline(self.x, self.y, order=order) - - def crop_x(self, start, stop): - ia, ib = np.searchsorted(self.x, (start, stop)) - if start > stop: - x = self.x[ia - 1:ib - 1:-1] - else: - x = self.x[ia:ib] - return np.r_[start, x, stop] - - def scale_x(self, x, scale, min_duration=1, min_length=20): - """Enforce, round, and scale x to device-dependent values. - - Due to minimum duration and/or minimum segment length constraints - this method may drop samples from `x_sample` to comply. - - :param min_duration: Minimum duration of a line. - :param min_length: Minimum segment length to space triggers. - """ - # We want to only sample a spline at t_knot + epsilon - # where the highest order derivative has just jumped - # and is valid at least up to the next knot after t_knot. - # - # To ensure that we are on the correct side of a knot: - # * only ever increase t when rounding (for increasing t) - # * or only ever decrease it (for decreasing t) - t = x/scale - inc = np.diff(t) >= 0 - inc = np.r_[inc, inc[-1]] - t = np.where(inc, np.ceil(t), np.floor(t)) - dt = np.diff(t.astype(int)) - - valid = np.absolute(dt) >= min_duration - if not np.any(valid): - valid[0] = True - dt[0] = max(dt[0], min_length) - dt = dt[valid] - x_sample = t[:-1][valid]*scale - return x_sample, dt - - def __call__(self, x): - return self.spline(x) - - -def discrete_compensate(c): - """Compensate spline coefficients for discrete accumulators - - Given continuous-time b-spline coefficients, this function - compensates for the effect of discrete time steps in the - target devices. - - The compensation is performed in-place. - """ - l = len(c) - if l > 2: - c[1] += c[2]/2. - if l > 3: - c[1] += c[3]/6. - c[2] += c[3] - if l > 4: - raise ValueError("only third-order splines supported") diff --git a/artiq/wavesynth/compute_samples.py b/artiq/wavesynth/compute_samples.py deleted file mode 100644 index 9b80f8298..000000000 --- a/artiq/wavesynth/compute_samples.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright (C) 2014, 2015 M-Labs Limited -# Copyright (C) 2014, 2015 Robert Jordens - -from copy import copy -from math import cos, pi - -from artiq.wavesynth.coefficients import discrete_compensate - - -class Spline: - def __init__(self): - self.c = [0.0] - - def set_coefficients(self, c): - if not c: - c = [0.] - self.c = copy(c) - discrete_compensate(self.c) - - def next(self): - r = self.c[0] - for i in range(len(self.c) - 1): - self.c[i] += self.c[i + 1] - return r - - -class SplinePhase: - def __init__(self): - self.c = [0.0] - self.c0 = 0.0 - - def set_coefficients(self, c): - if not c: - c = [0.] - self.c0 = c[0] - c1p = c[1:] - discrete_compensate(c1p) - self.c[1:] = c1p - - def clear(self): - self.c[0] = 0.0 - - def next(self): - r = self.c[0] - for i in range(len(self.c) - 1): - self.c[i] += self.c[i + 1] - self.c[i] %= 1.0 - return r + self.c0 - - -class DDS: - def __init__(self): - self.amplitude = Spline() - self.phase = SplinePhase() - - def next(self): - return self.amplitude.next()*cos(2*pi*self.phase.next()) - - -class Channel: - def __init__(self): - self.bias = Spline() - self.dds = DDS() - self.v = 0. - self.silence = False - - def next(self): - v = self.bias.next() + self.dds.next() - if not self.silence: - self.v = v - return self.v - - def set_silence(self, s): - self.silence = s - - -class TriggerError(Exception): - pass - - -class Synthesizer: - def __init__(self, nchannels, program): - self.channels = [Channel() for _ in range(nchannels)] - self.program = program - # line_iter is None: "wait for segment selection" state - # otherwise: iterator on the current position in the frame - self.line_iter = None - - def select(self, selection): - if self.line_iter is not None: - raise TriggerError("a frame is already selected") - self.line_iter = iter(self.program[selection]) - self.line = next(self.line_iter) - - def trigger(self): - if self.line_iter is None: - raise TriggerError("no frame selected") - - line = self.line - if not line.get("trigger", False): - raise TriggerError("segment is not triggered") - - r = [[] for _ in self.channels] - while True: - for channel, channel_data in zip(self.channels, - line["channel_data"]): - channel.set_silence(channel_data.get("silence", False)) - if "bias" in channel_data: - channel.bias.set_coefficients( - channel_data["bias"]["amplitude"]) - if "dds" in channel_data: - channel.dds.amplitude.set_coefficients( - channel_data["dds"]["amplitude"]) - if "phase" in channel_data["dds"]: - channel.dds.phase.set_coefficients( - channel_data["dds"]["phase"]) - if channel_data["dds"].get("clear", False): - channel.dds.phase.clear() - - if line.get("dac_divider", 1) != 1: - raise NotImplementedError - - for channel, rc in zip(self.channels, r): - for i in range(line["duration"]): - rc.append(channel.next()) - - try: - self.line = line = next(self.line_iter) - if line.get("trigger", False): - return r - except StopIteration: - self.line_iter = None - return r diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 175039862..5d1562267 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -47,12 +47,6 @@ Digital I/O drivers .. automodule:: artiq.coredevice.edge_counter :members: -:mod:`artiq.coredevice.shiftreg` module -+++++++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.shiftreg - :members: - :mod:`artiq.coredevice.spi2` module +++++++++++++++++++++++++++++++++++ @@ -104,25 +98,6 @@ RF generation drivers .. automodule:: artiq.coredevice.adf5356 :members: -:mod:`artiq.coredevice.spline` module -+++++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.spline - :members: - -:mod:`artiq.coredevice.sawg` module -+++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.sawg - :members: - - -:mod:`artiq.coredevice.basemod_att` module -++++++++++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.basemod_att - :members: - :mod:`artiq.coredevice.phaser` module +++++++++++++++++++++++++++++++++++++ @@ -150,12 +125,6 @@ DAC/ADC drivers .. automodule:: artiq.coredevice.sampler :members: -:mod:`artiq.coredevice.novogorny` module -++++++++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.novogorny - :members: - :mod:`artiq.coredevice.fastino` module ++++++++++++++++++++++++++++++++++++++++ diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index 5efe5baf3..843f03311 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -120,9 +120,6 @@ Core device RTIO analyzer tool :ref: artiq.frontend.artiq_coreanalyzer.get_argparser :prog: artiq_coreanalyzer -.. note:: - The RTIO analyzer does not support SAWG. - .. _routing-table-tool: DRTIO routing table manipulation tool diff --git a/flake.nix b/flake.nix index b8703bc3d..8d1c7c23a 100644 --- a/flake.nix +++ b/flake.nix @@ -135,18 +135,6 @@ propagatedBuildInputs = with pkgs.python3Packages; [ jinja2 numpy migen pyserial asyncserial ]; }; - jesd204b = pkgs.python3Packages.buildPythonPackage rec { - pname = "jesd204b"; - version = "unstable-2021-05-05"; - src = pkgs.fetchFromGitHub { - owner = "m-labs"; - repo = "jesd204b"; - rev = "bf1cd9014c8b7a9db67609f653634daaf3bcd39b"; - sha256 = "sha256-wyYOCRIPANReeCl+KaIpiAStsn2mzfMlK+cSrUzVrAw="; - }; - propagatedBuildInputs = with pkgs.python3Packages; [ migen misoc ]; - }; - microscope = pkgs.python3Packages.buildPythonPackage rec { pname = "microscope"; version = "unstable-2020-12-28"; @@ -356,7 +344,7 @@ devShell.x86_64-linux = pkgs.mkShell { name = "artiq-dev-shell"; buildInputs = [ - (packages.x86_64-linux.python3-mimalloc.withPackages(ps: with packages.x86_64-linux; [ migen misoc jesd204b artiq ps.paramiko ps.jsonschema microscope ])) + (packages.x86_64-linux.python3-mimalloc.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ps.paramiko ps.jsonschema microscope ])) rustPlatform.rust.rustc rustPlatform.rust.cargo cargo-xbuild From 5db9bc9bd473729ef508ab9ba6542873ac1f7499 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 08:55:08 +0800 Subject: [PATCH 084/352] edge_counter: port to nac3 --- artiq/coredevice/edge_counter.py | 57 ++++++++++++--------- artiq/examples/nac3devices/nac3devices.json | 7 +++ artiq/examples/nac3devices/nac3devices.py | 3 ++ 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/artiq/coredevice/edge_counter.py b/artiq/coredevice/edge_counter.py index e7782064e..52357fd53 100644 --- a/artiq/coredevice/edge_counter.py +++ b/artiq/coredevice/edge_counter.py @@ -51,11 +51,13 @@ See :mod:`artiq.gateware.rtio.phy.edge_counter` and :meth:`artiq.gateware.eem.DIO.add_std` for the gateware components. """ +from numpy import int32, int64 + +from artiq.coredevice.core import Core from artiq.language.core import * -from artiq.language.types import * from artiq.coredevice.rtio import (rtio_output, rtio_input_data, rtio_input_timestamped_data) -from numpy import int32, int64 + CONFIG_COUNT_RISING = 0b0001 CONFIG_COUNT_FALLING = 0b0010 @@ -63,12 +65,14 @@ CONFIG_SEND_COUNT_EVENT = 0b0100 CONFIG_RESET_TO_ZERO = 0b1000 +@nac3 class CounterOverflow(Exception): """Raised when an edge counter value is read which indicates that the counter might have overflowed.""" pass +@nac3 class EdgeCounter: """RTIO TTL edge counter driver driver. @@ -84,7 +88,9 @@ class EdgeCounter: the gateware needs to be rebuilt. """ - kernel_invariants = {"core", "channel", "counter_max"} + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + counter_max: KernelInvariant[int32] def __init__(self, dmgr, channel, gateware_width=31, core_device="core"): self.core = dmgr.get(core_device) @@ -92,7 +98,7 @@ class EdgeCounter: self.counter_max = (1 << (gateware_width - 1)) - 1 @kernel - def gate_rising(self, duration): + def gate_rising(self, duration: float) -> int64: """Count rising edges for the given duration and request the total at the end. @@ -106,7 +112,7 @@ class EdgeCounter: return self.gate_rising_mu(self.core.seconds_to_mu(duration)) @kernel - def gate_falling(self, duration): + def gate_falling(self, duration: float) -> int64: """Count falling edges for the given duration and request the total at the end. @@ -120,7 +126,7 @@ class EdgeCounter: return self.gate_falling_mu(self.core.seconds_to_mu(duration)) @kernel - def gate_both(self, duration): + def gate_both(self, duration: float) -> int64: """Count both rising and falling edges for the given duration, and request the total at the end. @@ -133,42 +139,43 @@ class EdgeCounter: """ return self.gate_both_mu(self.core.seconds_to_mu(duration)) + # NAC3TODO: restore keyword arguments in calls (https://git.m-labs.hk/M-Labs/nac3/issues/199) @kernel - def gate_rising_mu(self, duration_mu): + def gate_rising_mu(self, duration_mu: int64) -> int64: """See :meth:`gate_rising`.""" return self._gate_mu( - duration_mu, count_rising=True, count_falling=False) + duration_mu, True, False) @kernel - def gate_falling_mu(self, duration_mu): + def gate_falling_mu(self, duration_mu: int64) -> int64: """See :meth:`gate_falling`.""" return self._gate_mu( - duration_mu, count_rising=False, count_falling=True) + duration_mu, False, True) @kernel - def gate_both_mu(self, duration_mu): + def gate_both_mu(self, duration_mu: int64) -> int64: """See :meth:`gate_both_mu`.""" return self._gate_mu( - duration_mu, count_rising=True, count_falling=True) + duration_mu, True, True) @kernel - def _gate_mu(self, duration_mu, count_rising, count_falling): + def _gate_mu(self, duration_mu: int64, count_rising: bool, count_falling: bool) -> int64: self.set_config( - count_rising=count_rising, - count_falling=count_falling, - send_count_event=False, - reset_to_zero=True) + count_rising, + count_falling, + False, + True) delay_mu(duration_mu) self.set_config( - count_rising=False, - count_falling=False, - send_count_event=True, - reset_to_zero=False) + False, + False, + True, + False) return now_mu() @kernel - def set_config(self, count_rising: TBool, count_falling: TBool, - send_count_event: TBool, reset_to_zero: TBool): + def set_config(self, count_rising: bool, count_falling: bool, + send_count_event: bool, reset_to_zero: bool): """Emit an RTIO event at the current timeline position to set the gateware configuration. @@ -193,7 +200,7 @@ class EdgeCounter: rtio_output(self.channel << 8, config) @kernel - def fetch_count(self) -> TInt32: + def fetch_count(self) -> int32: """Wait for and return count total from previously requested input event. @@ -212,7 +219,7 @@ class EdgeCounter: @kernel def fetch_timestamped_count( - self, timeout_mu=int64(-1)) -> TTuple([TInt64, TInt32]): + self, timeout_mu: int64 = int64(-1)) -> tuple[int64, int32]: """Wait for and return the timestamp and count total of a previously requested input event. diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json index e57ec9fd7..a376ee3af 100644 --- a/artiq/examples/nac3devices/nac3devices.json +++ b/artiq/examples/nac3devices/nac3devices.json @@ -25,6 +25,13 @@ { "type": "sampler", "ports": [4] + }, + { + "type": "dio", + "ports": [5], + "bank_direction_low": "input", + "bank_direction_high": "output", + "edge_counter": true } ] } diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index 7a2943e18..474aa0cd7 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -6,6 +6,7 @@ from artiq.coredevice.adf5356 import ADF5356 from artiq.coredevice.urukul import CPLD as UrukulCPLD from artiq.coredevice.ad9912 import AD9912 from artiq.coredevice.sampler import Sampler +from artiq.coredevice.edge_counter import EdgeCounter @nac3 @@ -17,6 +18,7 @@ class NAC3Devices(EnvExperiment): urukul0_cpld: KernelInvariant[UrukulCPLD] urukul0_ch0: KernelInvariant[AD9912] sampler0: KernelInvariant[Sampler] + ttl0_counter: KernelInvariant[EdgeCounter] def build(self): self.setattr_device("core") @@ -26,6 +28,7 @@ class NAC3Devices(EnvExperiment): self.setattr_device("urukul0_cpld") self.setattr_device("urukul0_ch0") self.setattr_device("sampler0") + self.setattr_device("ttl0_counter") @kernel def run(self): From 6388b82455fff075c610e5bc48bf0d58e90aeb09 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 16:28:17 +0800 Subject: [PATCH 085/352] coredevice/cache: port to nac3 --- artiq/coredevice/cache.py | 22 ++++++++++++++-------- artiq/examples/nac3devices/nac3devices.py | 3 +++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/artiq/coredevice/cache.py b/artiq/coredevice/cache.py index 6c222bb6f..7db1d0128 100644 --- a/artiq/coredevice/cache.py +++ b/artiq/coredevice/cache.py @@ -1,23 +1,29 @@ -from artiq.language.core import * -from artiq.language.types import * +from numpy import int32 + +from artiq.language.core import nac3, extern, kernel, KernelInvariant +from artiq.coredevice.core import Core -@syscall(flags={"nounwind"}) -def cache_get(key: TStr) -> TList(TInt32): +@extern +def cache_get(key: str) -> list[int32]: raise NotImplementedError("syscall not simulated") -@syscall -def cache_put(key: TStr, value: TList(TInt32)) -> TNone: +@extern +def cache_put(key: str, value: list[int32]): raise NotImplementedError("syscall not simulated") +@nac3 class CoreCache: """Core device cache access""" + + core: KernelInvariant[Core] + def __init__(self, dmgr, core_device="core"): self.core = dmgr.get(core_device) @kernel - def get(self, key): + def get(self, key: str) -> list[int32]: """Extract a value from the core device cache. After a value is extracted, it cannot be replaced with another value using :meth:`put` until all kernel functions finish executing; attempting @@ -34,7 +40,7 @@ class CoreCache: return cache_get(key) @kernel - def put(self, key, value): + def put(self, key: str, value: list[int32]): """Put a value into the core device cache. The value will persist until reboot. To remove a value from the cache, call :meth:`put` with an empty list. diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index 474aa0cd7..051e56e0f 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -1,5 +1,6 @@ from artiq.experiment import * from artiq.coredevice.core import Core +from artiq.coredevice.cache import CoreCache from artiq.coredevice.zotino import Zotino from artiq.coredevice.mirny import Mirny as MirnyCPLD from artiq.coredevice.adf5356 import ADF5356 @@ -12,6 +13,7 @@ from artiq.coredevice.edge_counter import EdgeCounter @nac3 class NAC3Devices(EnvExperiment): core: KernelInvariant[Core] + core_cache: KernelInvariant[CoreCache] zotino0: KernelInvariant[Zotino] mirny0_cpld: KernelInvariant[MirnyCPLD] mirny0_ch0: KernelInvariant[ADF5356] @@ -22,6 +24,7 @@ class NAC3Devices(EnvExperiment): def build(self): self.setattr_device("core") + self.setattr_device("core_cache") self.setattr_device("zotino0") self.setattr_device("mirny0_cpld") self.setattr_device("mirny0_ch0") From 2d5114f32de5782ee6418c7ff6c7907915c3f49c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 16:45:12 +0800 Subject: [PATCH 086/352] remove legacy compiler test --- artiq/test/compiler/__init__.py | 0 artiq/test/compiler/test_domination.py | 166 ------------------------- 2 files changed, 166 deletions(-) delete mode 100644 artiq/test/compiler/__init__.py delete mode 100644 artiq/test/compiler/test_domination.py diff --git a/artiq/test/compiler/__init__.py b/artiq/test/compiler/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/artiq/test/compiler/test_domination.py b/artiq/test/compiler/test_domination.py deleted file mode 100644 index 0c4334617..000000000 --- a/artiq/test/compiler/test_domination.py +++ /dev/null @@ -1,166 +0,0 @@ -import unittest -from artiq.compiler.analyses.domination import DominatorTree, PostDominatorTree - -class MockBasicBlock: - def __init__(self, name): - self.name = name - self._successors = [] - self._predecessors = [] - - def successors(self): - return self._successors - - def predecessors(self): - return self._predecessors - - def set_successors(self, successors): - self._successors = list(successors) - for block in self._successors: - block._predecessors.append(self) - -class MockFunction: - def __init__(self, entry, basic_blocks): - self._entry = entry - self.basic_blocks = basic_blocks - - def entry(self): - return self._entry - -def makefn(entry_name, graph): - blocks = {} - for block_name in graph: - blocks[block_name] = MockBasicBlock(block_name) - for block_name in graph: - successors = list(map(lambda name: blocks[name], graph[block_name])) - blocks[block_name].set_successors(successors) - return MockFunction(blocks[entry_name], blocks.values()) - -def dom(function, domtree): - dom = {} - for block in function.basic_blocks: - dom[block.name] = [dom_block.name for dom_block in domtree.dominators(block)] - return dom - -def idom(function, domtree): - idom = {} - for block in function.basic_blocks: - idom_block = domtree.immediate_dominator(block) - idom[block.name] = idom_block.name if idom_block else None - return idom - -class TestDominatorTree(unittest.TestCase): - def test_linear(self): - func = makefn('A', { - 'A': ['B'], - 'B': ['C'], - 'C': [] - }) - domtree = DominatorTree(func) - self.assertEqual({ - 'C': 'B', 'B': 'A', 'A': 'A' - }, idom(func, domtree)) - self.assertEqual({ - 'C': ['C', 'B', 'A'], 'B': ['B', 'A'], 'A': ['A'] - }, dom(func, domtree)) - - def test_diamond(self): - func = makefn('A', { - 'A': ['C', 'B'], - 'B': ['D'], - 'C': ['D'], - 'D': [] - }) - domtree = DominatorTree(func) - self.assertEqual({ - 'D': 'A', 'C': 'A', 'B': 'A', 'A': 'A' - }, idom(func, domtree)) - - def test_combined(self): - func = makefn('A', { - 'A': ['B', 'D'], - 'B': ['C'], - 'C': ['E'], - 'D': ['E'], - 'E': [] - }) - domtree = DominatorTree(func) - self.assertEqual({ - 'A': 'A', 'B': 'A', 'C': 'B', 'D': 'A', 'E': 'A' - }, idom(func, domtree)) - - def test_figure_2(self): - func = makefn(5, { - 5: [3, 4], - 4: [1], - 3: [2], - 2: [1], - 1: [2] - }) - domtree = DominatorTree(func) - self.assertEqual({ - 1: 5, 2: 5, 3: 5, 4: 5, 5: 5 - }, idom(func, domtree)) - - def test_figure_4(self): - func = makefn(6, { - 6: [4, 5], - 5: [1], - 4: [3, 2], - 3: [2], - 2: [1, 3], - 1: [2] - }) - domtree = DominatorTree(func) - self.assertEqual({ - 1: 6, 2: 6, 3: 6, 4: 6, 5: 6, 6: 6 - }, idom(func, domtree)) - -class TestPostDominatorTree(unittest.TestCase): - def test_linear(self): - func = makefn('A', { - 'A': ['B'], - 'B': ['C'], - 'C': [] - }) - domtree = PostDominatorTree(func) - self.assertEqual({ - 'A': 'B', 'B': 'C', 'C': None - }, idom(func, domtree)) - - def test_diamond(self): - func = makefn('A', { - 'A': ['B', 'D'], - 'B': ['C'], - 'C': ['E'], - 'D': ['E'], - 'E': [] - }) - domtree = PostDominatorTree(func) - self.assertEqual({ - 'E': None, 'D': 'E', 'C': 'E', 'B': 'C', 'A': 'E' - }, idom(func, domtree)) - - def test_multi_exit(self): - func = makefn('A', { - 'A': ['B', 'C'], - 'B': [], - 'C': [] - }) - domtree = PostDominatorTree(func) - self.assertEqual({ - 'A': None, 'B': None, 'C': None - }, idom(func, domtree)) - - def test_multi_exit_diamond(self): - func = makefn('A', { - 'A': ['B', 'C'], - 'B': ['D'], - 'C': ['D'], - 'D': ['E', 'F'], - 'E': [], - 'F': [] - }) - domtree = PostDominatorTree(func) - self.assertEqual({ - 'A': 'D', 'B': 'D', 'C': 'D', 'D': None, 'E': None, 'F': None - }, idom(func, domtree)) From 892b96892f1d4c08db41c099864bc83f13f5a207 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 17:26:14 +0800 Subject: [PATCH 087/352] update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index e8819b1a3..9e7a800aa 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1645782167, - "narHash": "sha256-gLYGR0bFqKrzIErn3TLSpliUjfrzZoepuXwBEA5ov7E=", + "lastModified": 1645867753, + "narHash": "sha256-BzQjd5KhQ2Lt9NPmb5cJaggjRiCA+GfeCFIIyyZp/FM=", "ref": "master", - "rev": "e710b6c320e2da12ff8f40f9de66538a3083b2f6", - "revCount": 608, + "rev": "804d5db27e36da8ca6a046f20a43130d1cfe6e1e", + "revCount": 612, "type": "git", "url": "https://git.m-labs.hk/M-Labs/nac3.git" }, From 7b02918a437b8f446378401eca5a0b91e2cee90b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 17:39:59 +0800 Subject: [PATCH 088/352] worker_impl: port to NAC3 --- artiq/master/worker_impl.py | 34 ++++------------------------------ 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 29ec4e427..50896a946 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -20,6 +20,8 @@ from sipyco import pipe_ipc, pyon from sipyco.packed_exceptions import raise_packed_exc from sipyco.logging_tools import multiline_log_config +from nac3artiq import CompileError + import artiq from artiq import tools from artiq.master.worker_db import DeviceManager, DatasetManager, DummyDevice @@ -27,9 +29,7 @@ from artiq.language.environment import ( is_public_experiment, TraceArgumentManager, ProcessArgumentManager ) from artiq.language.core import set_watchdog_factory, TerminationRequested -from artiq.language.types import TBool from artiq.language import import_cache -from artiq.coredevice.core import CompileError, host_only, _render_diagnostic from artiq import __version__ as artiq_version @@ -98,13 +98,13 @@ class Scheduler: self.priority = priority pause_noexc = staticmethod(make_parent_action("pause")) - @host_only + def pause(self): if self.pause_noexc(): raise TerminationRequested _check_pause = staticmethod(make_parent_action("scheduler_check_pause")) - def check_pause(self, rid=None) -> TBool: + def check_pause(self, rid=None) -> bool: if rid is None: rid = self.rid return self._check_pause(rid) @@ -182,31 +182,6 @@ def examine(device_mgr, dataset_mgr, file): del sys.modules[key] -def setup_diagnostics(experiment_file, repository_path): - def render_diagnostic(self, diagnostic): - message = "While compiling {}\n".format(experiment_file) + \ - _render_diagnostic(diagnostic, colored=False) - if repository_path is not None: - message = message.replace(repository_path, "") - - if diagnostic.level == "warning": - logging.warning(message) - else: - logging.error(message) - - # This is kind of gross, but 1) we do not have any explicit connection - # between the worker and a coredevice.core.Core instance at all, - # and 2) the diagnostic engine really ought to be per-Core, since - # that's what uses it and the repository path is per-Core. - # So I don't know how to implement this properly for now. - # - # This hack is as good or bad as any other solution that involves - # putting inherently local objects (the diagnostic engine) into - # global slots, and there isn't any point in making it prettier by - # wrapping it in layers of indirection. - artiq.coredevice.core._DiagnosticEngine.render_diagnostic = \ - render_diagnostic - def put_completed(): put_object({"action": "completed"}) @@ -278,7 +253,6 @@ def main(): else: experiment_file = expid["file"] repository_path = None - setup_diagnostics(experiment_file, repository_path) exp = get_experiment(experiment_file, expid["class_name"]) device_mgr.virtual_devices["scheduler"].set_run_info( rid, obj["pipeline_name"], expid, obj["priority"]) From bea7e952fa334eeb69f27e01ab6a9b0155dd61cf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 17:41:48 +0800 Subject: [PATCH 089/352] edge_counter: restore keyword arguments --- artiq/coredevice/edge_counter.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/artiq/coredevice/edge_counter.py b/artiq/coredevice/edge_counter.py index 52357fd53..e560565fb 100644 --- a/artiq/coredevice/edge_counter.py +++ b/artiq/coredevice/edge_counter.py @@ -139,38 +139,37 @@ class EdgeCounter: """ return self.gate_both_mu(self.core.seconds_to_mu(duration)) - # NAC3TODO: restore keyword arguments in calls (https://git.m-labs.hk/M-Labs/nac3/issues/199) @kernel def gate_rising_mu(self, duration_mu: int64) -> int64: """See :meth:`gate_rising`.""" return self._gate_mu( - duration_mu, True, False) + duration_mu, count_rising=True, count_falling=False) @kernel def gate_falling_mu(self, duration_mu: int64) -> int64: """See :meth:`gate_falling`.""" return self._gate_mu( - duration_mu, False, True) + duration_mu, count_rising=False, count_falling=True) @kernel def gate_both_mu(self, duration_mu: int64) -> int64: """See :meth:`gate_both_mu`.""" return self._gate_mu( - duration_mu, True, True) + duration_mu, count_rising=True, count_falling=True) @kernel def _gate_mu(self, duration_mu: int64, count_rising: bool, count_falling: bool) -> int64: self.set_config( - count_rising, - count_falling, - False, - True) + count_rising=count_rising, + count_falling=count_falling, + send_count_event=False, + reset_to_zero=True) delay_mu(duration_mu) self.set_config( - False, - False, - True, - False) + count_rising=False, + count_falling=False, + send_count_event=True, + reset_to_zero=False) return now_mu() @kernel From d924d0cd205bbd7fc9337472e3ac829a1e3a52bd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 17:43:27 +0800 Subject: [PATCH 090/352] flake: work around allowedUris problem --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 8d1c7c23a..1a1c2edba 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,7 @@ inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; }; inputs.sipyco.url = github:m-labs/sipyco; inputs.sipyco.inputs.nixpkgs.follows = "nac3/nixpkgs"; - inputs.nac3 = { type = "git"; url = "https://git.m-labs.hk/M-Labs/nac3.git"; }; + inputs.nac3 = { type = "git"; url = "https://git.m-labs.hk/m-labs/nac3.git"; }; inputs.artiq-comtools.url = github:m-labs/artiq-comtools; inputs.artiq-comtools.inputs.nixpkgs.follows = "nac3/nixpkgs"; inputs.artiq-comtools.inputs.sipyco.follows = "sipyco"; From b9a359a45b73018464ec898d9b91763dee381393 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 17:50:41 +0800 Subject: [PATCH 091/352] fix flake.lock --- flake.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.lock b/flake.lock index 9e7a800aa..e00dff082 100644 --- a/flake.lock +++ b/flake.lock @@ -51,11 +51,11 @@ "rev": "804d5db27e36da8ca6a046f20a43130d1cfe6e1e", "revCount": 612, "type": "git", - "url": "https://git.m-labs.hk/M-Labs/nac3.git" + "url": "https://git.m-labs.hk/m-labs/nac3.git" }, "original": { "type": "git", - "url": "https://git.m-labs.hk/M-Labs/nac3.git" + "url": "https://git.m-labs.hk/m-labs/nac3.git" } }, "nixpkgs": { From d7c915ff7b629d4d5443123544a32657ce1a3079 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 17:56:02 +0800 Subject: [PATCH 092/352] test_cache: partially port to NAC3 --- artiq/coredevice/core.py | 1 + artiq/test/coredevice/test_cache.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index e4781fbec..8b55bd629 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -55,6 +55,7 @@ class Core: self.dmgr = dmgr self.core = self self.comm.core = self + self.target = target self.compiler = nac3artiq.NAC3(target) self.embedding_map = EmbeddingMap() diff --git a/artiq/test/coredevice/test_cache.py b/artiq/test/coredevice/test_cache.py index 07452cf07..5fc94e4ed 100644 --- a/artiq/test/coredevice/test_cache.py +++ b/artiq/test/coredevice/test_cache.py @@ -1,6 +1,5 @@ from artiq.experiment import * from artiq.coredevice.exceptions import CacheError -from artiq.compiler.targets import CortexA9Target from artiq.test.hardware_testbench import ExperimentCase @@ -41,7 +40,7 @@ class CacheTest(ExperimentCase): def test_borrow(self): exp = self.create(_Cache) - if exp.core.target_cls == CortexA9Target: + if exp.core.target == "cortexa9": self.skipTest("Zynq port memory management does not need CacheError") exp.put("x4", [1, 2, 3]) with self.assertRaises(CacheError): From 645c4590b336edfd763f7714696295682635b933 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 18:39:28 +0800 Subject: [PATCH 093/352] test: remove test_numpy (NAC3TODO) --- artiq/test/coredevice/test_numpy.py | 157 ---------------------------- 1 file changed, 157 deletions(-) delete mode 100644 artiq/test/coredevice/test_numpy.py diff --git a/artiq/test/coredevice/test_numpy.py b/artiq/test/coredevice/test_numpy.py deleted file mode 100644 index 7fe56f265..000000000 --- a/artiq/test/coredevice/test_numpy.py +++ /dev/null @@ -1,157 +0,0 @@ -from artiq.experiment import * -import numpy -import scipy.special -from artiq.test.hardware_testbench import ExperimentCase -from artiq.compiler.targets import CortexA9Target -from artiq.compiler import math_fns - - -class _RunOnDevice(EnvExperiment): - def build(self): - self.setattr_device("core") - - @kernel - def run_on_kernel_unary(self, a, callback, numpy, scipy): - self.run(a, callback, numpy, scipy) - - @kernel - def run_on_kernel_binary(self, a, b, callback, numpy, scipy): - self.run(a, b, callback, numpy, scipy) - - -# Binary operations supported for scalars and arrays of any dimension, including -# broadcasting. -ELEM_WISE_BINOPS = ["+", "*", "//", "%", "**", "-", "/"] - - -class CompareHostDeviceTest(ExperimentCase): - def _test_binop(self, op, a, b): - exp = self.create(_RunOnDevice) - exp.run = kernel_from_string(["a", "b", "callback", "numpy", "scipy"], - "callback(" + op + ")", - decorator=portable) - checked = False - - def with_host_result(host): - def with_both_results(device): - nonlocal checked - checked = True - self.assertTrue( - numpy.allclose(host, device, equal_nan=True), - "Discrepancy in binop test for '{}': Expexcted ({}, {}) -> {}, got {}" - .format(op, a, b, host, device)) - - exp.run_on_kernel_binary(a, b, with_both_results, numpy, scipy) - - exp.run(a, b, with_host_result, numpy, scipy) - self.assertTrue(checked, "Test did not run") - - def _test_unaryop(self, op, a): - exp = self.create(_RunOnDevice) - exp.run = kernel_from_string(["a", "callback", "numpy", "scipy"], - "callback(" + op + ")", - decorator=portable) - checked = False - - def with_host_result(host): - def with_both_results(device): - nonlocal checked - checked = True - self.assertTrue( - numpy.allclose(host, device, equal_nan=True), - "Discrepancy in unaryop test for '{}': Expexcted {} -> {}, got {}" - .format(op, a, host, device)) - - exp.run_on_kernel_unary(a, with_both_results, numpy, scipy) - - exp.run(a, with_host_result, numpy, scipy) - self.assertTrue(checked, "Test did not run") - - def test_scalar_scalar_binops(self): - # Some arbitrarily chosen arguments of different types. Could be turned into - # randomised tests instead. - # TODO: Provoke overflows, division by zero, etc., and compare results. - args = [(typ(a), typ(b)) for a, b in [(0, 1), (3, 2), (11, 6)] - for typ in [numpy.int32, numpy.int64, numpy.float64]] - for op in ELEM_WISE_BINOPS: - for arg in args: - self._test_binop("a" + op + "b", *arg) - - def test_scalar_matrix_binops(self): - for typ in [numpy.int32, numpy.int64, numpy.float64]: - scalar = typ(3) - matrix = numpy.array([[4, 5, 6], [7, 8, 9]], dtype=typ) - for op in ELEM_WISE_BINOPS: - code = "a" + op + "b" - self._test_binop(code, scalar, matrix) - self._test_binop(code, matrix, scalar) - self._test_binop(code, matrix, matrix) - - def test_matrix_mult(self): - for typ in [numpy.int32, numpy.int64, numpy.float64]: - mat_a = numpy.array([[1, 2, 3], [4, 5, 6]], dtype=typ) - mat_b = numpy.array([[7, 8], [9, 10], [11, 12]], dtype=typ) - self._test_binop("a @ b", mat_a, mat_b) - - def test_unary_math_fns(self): - names = [ - a for a, _ in math_fns.unary_fp_intrinsics + math_fns.unary_fp_runtime_calls - ] - exp = self.create(_RunOnDevice) - if exp.core.target_cls != CortexA9Target: - names.remove("exp2") - names.remove("log2") - names.remove("trunc") - for name in names: - op = "numpy.{}(a)".format(name) - # Avoid 0.5, as numpy.rint's rounding mode currently doesn't match. - self._test_unaryop(op, 0.51) - self._test_unaryop(op, numpy.array([[0.3, 0.4], [0.51, 0.6]])) - - def test_unary_scipy_fns(self): - names = [name for name, _ in math_fns.scipy_special_unary_runtime_calls] - if self.create(_RunOnDevice).core.target_cls != CortexA9Target: - names.remove("gamma") - for name in names: - op = "scipy.special.{}(a)".format(name) - self._test_unaryop(op, 0.5) - self._test_unaryop(op, numpy.array([[0.3, 0.4], [0.5, 0.6]])) - - def test_binary_math_fns(self): - names = [name for name, _ in math_fns.binary_fp_runtime_calls] - exp = self.create(_RunOnDevice) - if exp.core.target_cls != CortexA9Target: - names.remove("fmax") - names.remove("fmin") - for name in names: - code = "numpy.{}(a, b)".format(name) - # Avoid 0.5, as numpy.rint's rounding mode currently doesn't match. - self._test_binop(code, 1.0, 2.0) - self._test_binop(code, 1.0, numpy.array([2.0, 3.0])) - self._test_binop(code, numpy.array([1.0, 2.0]), 3.0) - self._test_binop(code, numpy.array([1.0, 2.0]), numpy.array([3.0, 4.0])) - - -class _MatrixMult(EnvExperiment): - """Regression test for GitHub #1578 (ICE when mixing different matrix multiplication - types in one kernel). - """ - def build(self): - self.setattr_device("core") - self.imat = numpy.arange(4, dtype=numpy.int64).reshape((2, 2)) - self.fmat = numpy.arange(4, dtype=numpy.float64).reshape((2, 2)) - - @kernel - def run(self): - self.verify(self.imat, self.imat, self.imat @ self.imat) - self.verify(self.imat, self.fmat, self.imat @ self.fmat) - self.verify(self.fmat, self.imat, self.fmat @ self.imat) - self.verify(self.fmat, self.fmat, self.fmat @ self.fmat) - - def verify(self, a, b, ab): - if not numpy.allclose(a @ b, ab): - raise ValueError("Mismatch for {} @ {}", a, b) - -class TestMatrixMult(ExperimentCase): - def test_multiple_matrix_mult_types(self): - self.create(_MatrixMult).run() From 2720bfa3982a36bc809e0820761aacc2aef4ebf2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 18:42:41 +0800 Subject: [PATCH 094/352] i2c: port syscalls to NAC3 --- artiq/coredevice/i2c.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/artiq/coredevice/i2c.py b/artiq/coredevice/i2c.py index 3608f4dc8..8962ddba2 100644 --- a/artiq/coredevice/i2c.py +++ b/artiq/coredevice/i2c.py @@ -2,34 +2,33 @@ Non-realtime drivers for I2C chips on the core device. """ - -from artiq.language.core import syscall, kernel -from artiq.language.types import TBool, TInt32, TNone +from numpy import int32 +from artiq.language.core import extern, kernel from artiq.coredevice.exceptions import I2CError -@syscall(flags={"nounwind", "nowrite"}) -def i2c_start(busno: TInt32) -> TNone: +@extern +def i2c_start(busno: int32): raise NotImplementedError("syscall not simulated") -@syscall(flags={"nounwind", "nowrite"}) -def i2c_restart(busno: TInt32) -> TNone: +@extern +def i2c_restart(busno: int32): raise NotImplementedError("syscall not simulated") -@syscall(flags={"nounwind", "nowrite"}) -def i2c_stop(busno: TInt32) -> TNone: +@extern +def i2c_stop(busno: int32): raise NotImplementedError("syscall not simulated") -@syscall(flags={"nounwind", "nowrite"}) -def i2c_write(busno: TInt32, b: TInt32) -> TBool: +@extern +def i2c_write(busno: int32, b: int32) -> bool: raise NotImplementedError("syscall not simulated") -@syscall(flags={"nounwind", "nowrite"}) -def i2c_read(busno: TInt32, ack: TBool) -> TInt32: +@extern +def i2c_read(busno: int32, ack: bool) -> int32: raise NotImplementedError("syscall not simulated") From 70531ae1e2fffc9f5307365aab1b996d541660a3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 18:47:07 +0800 Subject: [PATCH 095/352] ad9910: port imports and type annotations to NAC3 --- artiq/coredevice/ad9910.py | 182 ++++++++++++++++++------------------- 1 file changed, 90 insertions(+), 92 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 801b689ca..dd95114b0 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -1,9 +1,7 @@ from numpy import int32, int64 -from artiq.language.core import ( - kernel, delay, portable, delay_mu, now_mu, at_mu) +from artiq.language.core import kernel, portable from artiq.language.units import us, ms -from artiq.language.types import TBool, TInt32, TInt64, TFloat, TList, TTuple from artiq.coredevice import spi2 as spi from artiq.coredevice import urukul @@ -187,7 +185,7 @@ class AD9910: self.phase_mode = PHASE_MODE_CONTINUOUS @kernel - def set_phase_mode(self, phase_mode: TInt32): + def set_phase_mode(self, phase_mode: int32): r"""Set the default phase mode. for future calls to :meth:`set` and @@ -232,7 +230,7 @@ class AD9910: self.phase_mode = phase_mode @kernel - def write16(self, addr: TInt32, data: TInt32): + def write16(self, addr: int32, data: int32): """Write to 16 bit register. :param addr: Register address @@ -243,7 +241,7 @@ class AD9910: self.bus.write((addr << 24) | ((data & 0xffff) << 8)) @kernel - def write32(self, addr: TInt32, data: TInt32): + def write32(self, addr: int32, data: int32): """Write to 32 bit register. :param addr: Register address @@ -257,7 +255,7 @@ class AD9910: self.bus.write(data) @kernel - def read16(self, addr: TInt32) -> TInt32: + def read16(self, addr: int32) -> int32: """Read from 16 bit register. :param addr: Register address @@ -272,7 +270,7 @@ class AD9910: return self.bus.read() @kernel - def read32(self, addr: TInt32) -> TInt32: + def read32(self, addr: int32) -> int32: """Read from 32 bit register. :param addr: Register address @@ -287,7 +285,7 @@ class AD9910: return self.bus.read() @kernel - def read64(self, addr: TInt32) -> TInt64: + def read64(self, addr: int32) -> int64: """Read from 64 bit register. :param addr: Register address @@ -310,7 +308,7 @@ class AD9910: return (int64(hi) << 32) | lo @kernel - def write64(self, addr: TInt32, data_high: TInt32, data_low: TInt32): + def write64(self, addr: int32, data_high: int32, data_low: int32): """Write to 64 bit register. :param addr: Register address @@ -328,7 +326,7 @@ class AD9910: self.bus.write(data_low) @kernel - def write_ram(self, data: TList(TInt32)): + def write_ram(self, data: list[int32]): """Write data to RAM. The profile to write to and the step, start, and end address @@ -349,7 +347,7 @@ class AD9910: self.bus.write(data[len(data) - 1]) @kernel - def read_ram(self, data: TList(TInt32)): + def read_ram(self, data: list[int32]): """Read data from RAM. The profile to read from and the step, start, and end address @@ -379,17 +377,17 @@ class AD9910: @kernel def set_cfr1(self, - power_down: TInt32 = 0b0000, - phase_autoclear: TInt32 = 0, - drg_load_lrr: TInt32 = 0, - drg_autoclear: TInt32 = 0, - phase_clear: TInt32 = 0, - internal_profile: TInt32 = 0, - ram_destination: TInt32 = 0, - ram_enable: TInt32 = 0, - manual_osk_external: TInt32 = 0, - osk_enable: TInt32 = 0, - select_auto_osk: TInt32 = 0): + power_down: int32 = 0b0000, + phase_autoclear: int32 = 0, + drg_load_lrr: int32 = 0, + drg_autoclear: int32 = 0, + phase_clear: int32 = 0, + internal_profile: int32 = 0, + ram_destination: int32 = 0, + ram_enable: int32 = 0, + manual_osk_external: int32 = 0, + osk_enable: int32 = 0, + select_auto_osk: int32 = 0): """Set CFR1. See the AD9910 datasheet for parameter meanings. This method does not pulse IO_UPDATE. @@ -424,11 +422,11 @@ class AD9910: @kernel def set_cfr2(self, - asf_profile_enable: TInt32 = 1, - drg_enable: TInt32 = 0, - effective_ftw: TInt32 = 1, - sync_validation_disable: TInt32 = 0, - matched_latency_enable: TInt32 = 0): + asf_profile_enable: int32 = 1, + drg_enable: int32 = 0, + effective_ftw: int32 = 1, + sync_validation_disable: int32 = 0, + matched_latency_enable: int32 = 0): """Set CFR2. See the AD9910 datasheet for parameter meanings. This method does not pulse IO_UPDATE. @@ -452,7 +450,7 @@ class AD9910: (sync_validation_disable << 5)) @kernel - def init(self, blind: TBool = False): + def init(self, blind: bool = False): """Initialize and configure the DDS. Sets up SPI mode, confirms chip presence, powers down unused blocks, @@ -511,7 +509,7 @@ class AD9910: delay(1 * ms) @kernel - def power_down(self, bits: TInt32 = 0b1111): + def power_down(self, bits: int32 = 0b1111): """Power down DDS. :param bits: Power down bits, see datasheet @@ -520,11 +518,11 @@ class AD9910: self.cpld.io_update.pulse(1 * us) @kernel - def set_mu(self, ftw: TInt32 = 0, pow_: TInt32 = 0, asf: TInt32 = 0x3fff, - phase_mode: TInt32 = _PHASE_MODE_DEFAULT, - ref_time_mu: TInt64 = int64(-1), - profile: TInt32 = DEFAULT_PROFILE, - ram_destination: TInt32 = -1) -> TInt32: + def set_mu(self, ftw: int32 = 0, pow_: int32 = 0, asf: int32 = 0x3fff, + phase_mode: int32 = _PHASE_MODE_DEFAULT, + ref_time_mu: int64 = int64(-1), + profile: int32 = DEFAULT_PROFILE, + ram_destination: int32 = -1) -> int32: """Set DDS data in machine units. This uses machine units (FTW, POW, ASF). The frequency tuning word @@ -593,8 +591,8 @@ class AD9910: return pow_ @kernel - def get_mu(self, profile: TInt32 = DEFAULT_PROFILE - ) -> TTuple([TInt32, TInt32, TInt32]): + def get_mu(self, profile: int32 = DEFAULT_PROFILE + ) -> tuple[int32, int32, int32]: """Get the frequency tuning word, phase offset word, and amplitude scale factor. @@ -613,10 +611,10 @@ class AD9910: return ftw, pow_, asf @kernel - def set_profile_ram(self, start: TInt32, end: TInt32, step: TInt32 = 1, - profile: TInt32 = _DEFAULT_PROFILE_RAM, - nodwell_high: TInt32 = 0, zero_crossing: TInt32 = 0, - mode: TInt32 = 1): + def set_profile_ram(self, start: int32, end: int32, step: int32 = 1, + profile: int32 = _DEFAULT_PROFILE_RAM, + nodwell_high: int32 = 0, zero_crossing: int32 = 0, + mode: int32 = 1): """Set the RAM profile settings. :param start: Profile start address in RAM. @@ -640,7 +638,7 @@ class AD9910: self.write64(_AD9910_REG_PROFILE0 + profile, hi, lo) @kernel - def set_ftw(self, ftw: TInt32): + def set_ftw(self, ftw: int32): """Set the value stored to the AD9910's frequency tuning word (FTW) register. @@ -649,7 +647,7 @@ class AD9910: self.write32(_AD9910_REG_FTW, ftw) @kernel - def set_asf(self, asf: TInt32): + def set_asf(self, asf: int32): """Set the value stored to the AD9910's amplitude scale factor (ASF) register. @@ -658,7 +656,7 @@ class AD9910: self.write32(_AD9910_REG_ASF, asf << 2) @kernel - def set_pow(self, pow_: TInt32): + def set_pow(self, pow_: int32): """Set the value stored to the AD9910's phase offset word (POW) register. @@ -667,7 +665,7 @@ class AD9910: self.write16(_AD9910_REG_POW, pow_) @kernel - def get_ftw(self) -> TInt32: + def get_ftw(self) -> int32: """Get the value stored to the AD9910's frequency tuning word (FTW) register. @@ -676,7 +674,7 @@ class AD9910: return self.read32(_AD9910_REG_FTW) @kernel - def get_asf(self) -> TInt32: + def get_asf(self) -> int32: """Get the value stored to the AD9910's amplitude scale factor (ASF) register. @@ -685,7 +683,7 @@ class AD9910: return self.read32(_AD9910_REG_ASF) >> 2 @kernel - def get_pow(self) -> TInt32: + def get_pow(self) -> int32: """Get the value stored to the AD9910's phase offset word (POW) register. @@ -693,34 +691,34 @@ class AD9910: """ return self.read16(_AD9910_REG_POW) - @portable(flags={"fast-math"}) - def frequency_to_ftw(self, frequency: TFloat) -> TInt32: + @portable + def frequency_to_ftw(self, frequency: float) -> int32: """Return the 32-bit frequency tuning word corresponding to the given frequency. """ return int32(round(self.ftw_per_hz * frequency)) - @portable(flags={"fast-math"}) - def ftw_to_frequency(self, ftw: TInt32) -> TFloat: + @portable + def ftw_to_frequency(self, ftw: int32) -> float: """Return the frequency corresponding to the given frequency tuning word. """ return ftw / self.ftw_per_hz - @portable(flags={"fast-math"}) - def turns_to_pow(self, turns: TFloat) -> TInt32: + @portable + def turns_to_pow(self, turns: float) -> int32: """Return the 16-bit phase offset word corresponding to the given phase in turns.""" return int32(round(turns * 0x10000)) & int32(0xffff) - @portable(flags={"fast-math"}) - def pow_to_turns(self, pow_: TInt32) -> TFloat: + @portable + def pow_to_turns(self, pow_: int32) -> float: """Return the phase in turns corresponding to a given phase offset word.""" return pow_ / 0x10000 - @portable(flags={"fast-math"}) - def amplitude_to_asf(self, amplitude: TFloat) -> TInt32: + @portable + def amplitude_to_asf(self, amplitude: float) -> int32: """Return 14-bit amplitude scale factor corresponding to given fractional amplitude.""" code = int32(round(amplitude * 0x3fff)) @@ -728,14 +726,14 @@ class AD9910: raise ValueError("Invalid AD9910 fractional amplitude!") return code - @portable(flags={"fast-math"}) - def asf_to_amplitude(self, asf: TInt32) -> TFloat: + @portable + def asf_to_amplitude(self, asf: int32) -> float: """Return amplitude as a fraction of full scale corresponding to given amplitude scale factor.""" return asf / float(0x3fff) - @portable(flags={"fast-math"}) - def frequency_to_ram(self, frequency: TList(TFloat), ram: TList(TInt32)): + @portable + def frequency_to_ram(self, frequency: list[float], ram: list[int32]): """Convert frequency values to RAM profile data. To be used with :const:`RAM_DEST_FTW`. @@ -747,8 +745,8 @@ class AD9910: for i in range(len(ram)): ram[i] = self.frequency_to_ftw(frequency[i]) - @portable(flags={"fast-math"}) - def turns_to_ram(self, turns: TList(TFloat), ram: TList(TInt32)): + @portable + def turns_to_ram(self, turns: list[float], ram: list[int32]): """Convert phase values to RAM profile data. To be used with :const:`RAM_DEST_POW`. @@ -760,8 +758,8 @@ class AD9910: for i in range(len(ram)): ram[i] = self.turns_to_pow(turns[i]) << 16 - @portable(flags={"fast-math"}) - def amplitude_to_ram(self, amplitude: TList(TFloat), ram: TList(TInt32)): + @portable + def amplitude_to_ram(self, amplitude: list[float], ram: list[int32]): """Convert amplitude values to RAM profile data. To be used with :const:`RAM_DEST_ASF`. @@ -773,9 +771,9 @@ class AD9910: for i in range(len(ram)): ram[i] = self.amplitude_to_asf(amplitude[i]) << 18 - @portable(flags={"fast-math"}) - def turns_amplitude_to_ram(self, turns: TList(TFloat), - amplitude: TList(TFloat), ram: TList(TInt32)): + @portable + def turns_amplitude_to_ram(self, turns: list[float], + amplitude: list[float], ram: list[int32]): """Convert phase and amplitude values to RAM profile data. To be used with :const:`RAM_DEST_POWASF`. @@ -790,7 +788,7 @@ class AD9910: self.amplitude_to_asf(amplitude[i]) << 2) @kernel - def set_frequency(self, frequency: TFloat): + def set_frequency(self, frequency: float): """Set the value stored to the AD9910's frequency tuning word (FTW) register. @@ -799,7 +797,7 @@ class AD9910: self.set_ftw(self.frequency_to_ftw(frequency)) @kernel - def set_amplitude(self, amplitude: TFloat): + def set_amplitude(self, amplitude: float): """Set the value stored to the AD9910's amplitude scale factor (ASF) register. @@ -808,7 +806,7 @@ class AD9910: self.set_asf(self.amplitude_to_asf(amplitude)) @kernel - def set_phase(self, turns: TFloat): + def set_phase(self, turns: float): """Set the value stored to the AD9910's phase offset word (POW) register. @@ -817,7 +815,7 @@ class AD9910: self.set_pow(self.turns_to_pow(turns)) @kernel - def get_frequency(self) -> TFloat: + def get_frequency(self) -> float: """Get the value stored to the AD9910's frequency tuning word (FTW) register. @@ -826,7 +824,7 @@ class AD9910: return self.ftw_to_frequency(self.get_ftw()) @kernel - def get_amplitude(self) -> TFloat: + def get_amplitude(self) -> float: """Get the value stored to the AD9910's amplitude scale factor (ASF) register. @@ -835,7 +833,7 @@ class AD9910: return self.asf_to_amplitude(self.get_asf()) @kernel - def get_phase(self) -> TFloat: + def get_phase(self) -> float: """Get the value stored to the AD9910's phase offset word (POW) register. @@ -844,10 +842,10 @@ class AD9910: return self.pow_to_turns(self.get_pow()) @kernel - def set(self, frequency: TFloat = 0.0, phase: TFloat = 0.0, - amplitude: TFloat = 1.0, phase_mode: TInt32 = _PHASE_MODE_DEFAULT, - ref_time_mu: TInt64 = int64(-1), profile: TInt32 = DEFAULT_PROFILE, - ram_destination: TInt32 = -1) -> TFloat: + def set(self, frequency: float = 0.0, phase: float = 0.0, + amplitude: float = 1.0, phase_mode: int32 = _PHASE_MODE_DEFAULT, + ref_time_mu: int64 = int64(-1), profile: int32 = DEFAULT_PROFILE, + ram_destination: int32 = -1) -> float: """Set DDS data in SI units. .. seealso:: :meth:`set_mu` @@ -867,8 +865,8 @@ class AD9910: profile, ram_destination)) @kernel - def get(self, profile: TInt32 = DEFAULT_PROFILE - ) -> TTuple([TFloat, TFloat, TFloat]): + def get(self, profile: int32 = DEFAULT_PROFILE + ) -> tuple[float, float, float]: """Get the frequency, phase, and amplitude. .. seealso:: :meth:`get_mu` @@ -884,7 +882,7 @@ class AD9910: self.asf_to_amplitude(asf)) @kernel - def set_att_mu(self, att: TInt32): + def set_att_mu(self, att: int32): """Set digital step attenuator in machine units. This method will write the attenuator settings of all four channels. @@ -896,7 +894,7 @@ class AD9910: self.cpld.set_att_mu(self.chip_select - 4, att) @kernel - def set_att(self, att: TFloat): + def set_att(self, att: float): """Set digital step attenuator in SI units. This method will write the attenuator settings of all four channels. @@ -908,7 +906,7 @@ class AD9910: self.cpld.set_att(self.chip_select - 4, att) @kernel - def get_att_mu(self) -> TInt32: + def get_att_mu(self) -> int32: """Get digital step attenuator value in machine units. .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.get_channel_att_mu` @@ -918,7 +916,7 @@ class AD9910: return self.cpld.get_channel_att_mu(self.chip_select - 4) @kernel - def get_att(self) -> TFloat: + def get_att(self) -> float: """Get digital step attenuator value in SI units. .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.get_channel_att` @@ -928,7 +926,7 @@ class AD9910: return self.cpld.get_channel_att(self.chip_select - 4) @kernel - def cfg_sw(self, state: TBool): + def cfg_sw(self, state: bool): """Set CPLD CFG RF switch state. The RF switch is controlled by the logical or of the CPLD configuration shift register RF switch bit and the SW TTL line (if used). @@ -939,9 +937,9 @@ class AD9910: @kernel def set_sync(self, - in_delay: TInt32, - window: TInt32, - en_sync_gen: TInt32 = 0): + in_delay: int32, + window: int32, + en_sync_gen: int32 = 0): """Set the relevant parameters in the multi device synchronization register. See the AD9910 datasheet for details. The SYNC clock generator preset value is set to zero, and the SYNC_OUT generator is @@ -981,7 +979,7 @@ class AD9910: @kernel def tune_sync_delay(self, - search_seed: TInt32 = 15) -> TTuple([TInt32, TInt32]): + search_seed: int32 = 15) -> tuple[int32, int32]: """Find a stable SYNC_IN delay. This method first locates a valid SYNC_IN delay at zero validation @@ -1037,8 +1035,8 @@ class AD9910: raise ValueError("no valid window/delay") @kernel - def measure_io_update_alignment(self, delay_start: TInt64, - delay_stop: TInt64) -> TInt32: + def measure_io_update_alignment(self, delay_start: int64, + delay_stop: int64) -> int32: """Use the digital ramp generator to locate the alignment between IO_UPDATE and SYNC_CLK. @@ -1080,7 +1078,7 @@ class AD9910: return ftw & 1 @kernel - def tune_io_update_delay(self) -> TInt32: + def tune_io_update_delay(self) -> int32: """Find a stable IO_UPDATE delay alignment. Scan through increasing IO_UPDATE delays until a delay is found that From 9a05907b7af52b8a48a66f42a202012d73c5912e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 18:47:59 +0800 Subject: [PATCH 096/352] test_embedding: port imports and type annotations to NAC3 --- artiq/test/coredevice/test_embedding.py | 47 +++++++++++++------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 4e86e9aa5..55fa79c94 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -1,4 +1,5 @@ import numpy +from numpy import int32, int64 import unittest from time import sleep @@ -103,7 +104,7 @@ class _DefaultArg(EnvExperiment): def build(self): self.setattr_device("core") - def test(self, foo=42) -> TInt32: + def test(self, foo=42) -> int32: return foo @kernel @@ -121,40 +122,40 @@ class _RPCTypes(EnvExperiment): def build(self): self.setattr_device("core") - def return_bool(self) -> TBool: + def return_bool(self) -> bool: return True - def return_int32(self) -> TInt32: + def return_int32(self) -> int32: return 1 - def return_int64(self) -> TInt64: + def return_int64(self) -> int64: return 0x100000000 - def return_float(self) -> TFloat: + def return_float(self) -> float: return 1.0 - def return_str(self) -> TStr: + def return_str(self) -> str: return "foo" - def return_bytes(self) -> TBytes: + def return_bytes(self) -> bytes: return b"foo" - def return_bytearray(self) -> TByteArray: + def return_bytearray(self) -> bytearray: return bytearray(b"foo") - def return_tuple(self) -> TTuple([TInt32, TInt32]): + def return_tuple(self) -> tuple[int32, int32]: return (1, 2) - def return_list(self) -> TList(TInt32): + def return_list(self) -> list[int32]: return [2, 3] - def return_range(self) -> TRange32: + def return_range(self) -> range: return range(10) - def return_array(self) -> TArray(TInt32): + def return_array(self) -> numpy.ndarray: # NAC3TODO [int32] return numpy.array([1, 2]) - def return_matrix(self) -> TArray(TInt32, 2): + def return_matrix(self) -> numpy.ndarray: # NAC3TODO [int32, 2] return numpy.array([[1, 2], [3, 4]]) def return_mismatch(self): @@ -221,10 +222,10 @@ class _RPCCalls(EnvExperiment): self.setattr_device("core") self._list_int64 = [numpy.int64(1)] - def args(self, *args) -> TInt32: + def args(self, *args) -> int32: return len(args) - def kwargs(self, x="", **kwargs) -> TInt32: + def kwargs(self, x="", **kwargs) -> int32: return len(kwargs) @kernel @@ -304,11 +305,11 @@ class _Annotation(EnvExperiment): self.setattr_device("core") @kernel - def overflow(self, x: TInt64) -> TBool: + def overflow(self, x: int64) -> bool: return (x << 32) != 0 @kernel - def monomorphize(self, x: TList(TInt32)): + def monomorphize(self, x: list[int32]): pass @@ -382,10 +383,10 @@ class _ListTuple(EnvExperiment): if data[i] != data[0] + i: raise ValueError - def get_num_iters(self) -> TInt32: + def get_num_iters(self) -> int32: return 2 - def get_values(self, base_a, base_b, n) -> TTuple([TList(TInt32), TList(TInt32)]): + def get_values(self, base_a, base_b, n) -> tuple[list[int32], list[int32]]: return [numpy.int32(base_a + i) for i in range(n)], \ [numpy.int32(base_b + i) for i in range(n)] @@ -396,8 +397,8 @@ class _NestedTupleList(EnvExperiment): self.data = [(0x12345678, [("foo", [0.0, 1.0], [2, 3])]), (0x76543210, [("bar", [4.0, 5.0], [6, 7])])] - def get_data(self) -> TList(TTuple( - [TInt32, TList(TTuple([TStr, TList(TFloat), TList(TInt32)]))])): + def get_data(self) -> list[tuple + [int32, list[tuple[str, list[float], list[int32]]]]]: return self.data @kernel @@ -411,7 +412,7 @@ class _EmptyList(EnvExperiment): def build(self): self.setattr_device("core") - def get_empty(self) -> TList(TInt32): + def get_empty(self) -> list[int32]: return [] @kernel @@ -522,7 +523,7 @@ class _Alignment(EnvExperiment): self.setattr_device("core") @rpc - def a_tuple(self) -> TList(TTuple([TBool, TFloat, TBool])): + def a_tuple(self) -> list[tuple[bool, float, bool]]: return [(True, 1234.5678, True)] @kernel From 6eb1c4e138b0b0405d10fda3bb420bce652822c4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 18:49:45 +0800 Subject: [PATCH 097/352] sim: fix import for NAC3 --- artiq/sim/devices.py | 2 +- artiq/sim/time.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/sim/devices.py b/artiq/sim/devices.py index 41b7b59c5..3e2295bf6 100644 --- a/artiq/sim/devices.py +++ b/artiq/sim/devices.py @@ -1,7 +1,7 @@ from random import Random import numpy -from artiq.language.core import delay, at_mu, kernel +from artiq.language.core import kernel from artiq.sim import time diff --git a/artiq/sim/time.py b/artiq/sim/time.py index 72cd3313f..676966735 100644 --- a/artiq/sim/time.py +++ b/artiq/sim/time.py @@ -70,4 +70,4 @@ class Manager: return r manager = Manager() -core_language.set_time_manager(manager) +# NAC3TODO core_language.set_time_manager(manager) From 0e20058da336508ce703163ffe7547b6d45bed67 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 18:52:15 +0800 Subject: [PATCH 098/352] test_performance: port imports and type annotations to NAC3 --- artiq/test/coredevice/test_performance.py | 49 ++++++++++++----------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index 3ca1f86ba..2786dc551 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -2,6 +2,7 @@ import os import time import unittest import numpy +from numpy import int32, float64 from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase @@ -14,8 +15,8 @@ bytes_small = b"\x00" * (1 << 10) list_large = [123] * (1 << 18) list_small = [123] * (1 << 8) -array_large = numpy.array(list_large, numpy.int32) -array_small = numpy.array(list_small, numpy.int32) +array_large = numpy.array(list_large, int32) +array_small = numpy.array(list_small, int32) byte_list_large = [True] * (1 << 20) byte_list_small = [True] * (1 << 10) @@ -32,35 +33,35 @@ class _Transfer(EnvExperiment): self.d2h = [0.0] * self.count @rpc - def get_bytes(self, large: TBool) -> TBytes: + def get_bytes(self, large: bool) -> bytes: if large: return bytes_large else: return bytes_small @rpc - def get_list(self, large: TBool) -> TList(TInt32): + def get_list(self, large: bool) -> list[int32]: if large: return list_large else: return list_small @rpc - def get_byte_list(self, large: TBool) -> TList(TBool): + def get_byte_list(self, large: bool) -> list[bool]: if large: return byte_list_large else: return byte_list_small @rpc - def get_array(self, large: TBool) -> TArray(TInt32): + def get_array(self, large: bool) -> numpy.ndarray: # NAC3TODO: [int32] if large: return array_large else: return array_small @rpc - def get_string_list(self) -> TList(TStr): + def get_string_list(self) -> list[str]: return string_list @rpc @@ -77,7 +78,7 @@ class _Transfer(EnvExperiment): time_end = time.time() @rpc - def get_async_throughput(self) -> TFloat: + def get_async_throughput(self) -> float: return 128.0 / (time_end - time_start) @kernel @@ -171,8 +172,8 @@ class TransferTest(ExperimentCase): def test_bytes_large(self): exp = self.create(_Transfer) results = exp.test_bytes(True) - host_to_device = (1 << 20) / numpy.array(results[0], numpy.float64) - device_to_host = (1 << 20) / numpy.array(results[1], numpy.float64) + host_to_device = (1 << 20) / numpy.array(results[0], float64) + device_to_host = (1 << 20) / numpy.array(results[1], float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["Bytes (1MB) H2D", host_to_device.mean(), @@ -183,8 +184,8 @@ class TransferTest(ExperimentCase): def test_bytes_small(self): exp = self.create(_Transfer) results = exp.test_bytes(False) - host_to_device = (1 << 10) / numpy.array(results[0], numpy.float64) - device_to_host = (1 << 10) / numpy.array(results[1], numpy.float64) + host_to_device = (1 << 10) / numpy.array(results[0], float64) + device_to_host = (1 << 10) / numpy.array(results[1], float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["Bytes (1KB) H2D", host_to_device.mean(), @@ -195,8 +196,8 @@ class TransferTest(ExperimentCase): def test_byte_list_large(self): exp = self.create(_Transfer) results = exp.test_byte_list(True) - host_to_device = (1 << 20) / numpy.array(results[0], numpy.float64) - device_to_host = (1 << 20) / numpy.array(results[1], numpy.float64) + host_to_device = (1 << 20) / numpy.array(results[0], float64) + device_to_host = (1 << 20) / numpy.array(results[1], float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["Bytes List (1MB) H2D", host_to_device.mean(), @@ -207,8 +208,8 @@ class TransferTest(ExperimentCase): def test_byte_list_small(self): exp = self.create(_Transfer) results = exp.test_byte_list(False) - host_to_device = (1 << 10) / numpy.array(results[0], numpy.float64) - device_to_host = (1 << 10) / numpy.array(results[1], numpy.float64) + host_to_device = (1 << 10) / numpy.array(results[0], float64) + device_to_host = (1 << 10) / numpy.array(results[1], float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["Bytes List (1KB) H2D", host_to_device.mean(), @@ -219,8 +220,8 @@ class TransferTest(ExperimentCase): def test_list_large(self): exp = self.create(_Transfer) results = exp.test_list(True) - host_to_device = (1 << 20) / numpy.array(results[0], numpy.float64) - device_to_host = (1 << 20) / numpy.array(results[1], numpy.float64) + host_to_device = (1 << 20) / numpy.array(results[0], float64) + device_to_host = (1 << 20) / numpy.array(results[1], float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["I32 List (1MB) H2D", host_to_device.mean(), @@ -231,8 +232,8 @@ class TransferTest(ExperimentCase): def test_list_small(self): exp = self.create(_Transfer) results = exp.test_list(False) - host_to_device = (1 << 10) / numpy.array(results[0], numpy.float64) - device_to_host = (1 << 10) / numpy.array(results[1], numpy.float64) + host_to_device = (1 << 10) / numpy.array(results[0], float64) + device_to_host = (1 << 10) / numpy.array(results[1], float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["I32 List (1KB) H2D", host_to_device.mean(), @@ -243,8 +244,8 @@ class TransferTest(ExperimentCase): def test_array_large(self): exp = self.create(_Transfer) results = exp.test_array(True) - host_to_device = (1 << 20) / numpy.array(results[0], numpy.float64) - device_to_host = (1 << 20) / numpy.array(results[1], numpy.float64) + host_to_device = (1 << 20) / numpy.array(results[0], float64) + device_to_host = (1 << 20) / numpy.array(results[1], float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["I32 Array (1MB) H2D", host_to_device.mean(), @@ -255,8 +256,8 @@ class TransferTest(ExperimentCase): def test_array_small(self): exp = self.create(_Transfer) results = exp.test_array(False) - host_to_device = (1 << 10) / numpy.array(results[0], numpy.float64) - device_to_host = (1 << 10) / numpy.array(results[1], numpy.float64) + host_to_device = (1 << 10) / numpy.array(results[0], float64) + device_to_host = (1 << 10) / numpy.array(results[1], float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["I32 Array (1KB) H2D", host_to_device.mean(), From a606afa3bddc8f626082cb619ee581ffd14993f3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 18:52:40 +0800 Subject: [PATCH 099/352] test_phaser: port imports to NAC3 --- artiq/test/coredevice/test_phaser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_phaser.py b/artiq/test/coredevice/test_phaser.py index 18aac6a57..4f23f67db 100644 --- a/artiq/test/coredevice/test_phaser.py +++ b/artiq/test/coredevice/test_phaser.py @@ -1,7 +1,7 @@ import unittest from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase -from artiq.language.core import kernel, delay +from artiq.language.core import kernel from artiq.language.units import us From 5acf008be376ee4820f744097da526e7626b9397 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 18:52:56 +0800 Subject: [PATCH 100/352] test_rtio: port imports to NAC3 --- artiq/test/coredevice/test_rtio.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 3313b5c14..20a8d0ed6 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -12,7 +12,6 @@ from artiq.coredevice import exceptions from artiq.coredevice.comm_mgmt import CommMgmt from artiq.coredevice.comm_analyzer import (StoppedMessage, OutputMessage, InputMessage, decode_dump, get_analyzer_dump) -from artiq.compiler.targets import CortexA9Target artiq_low_latency = os.getenv("ARTIQ_LOW_LATENCY") @@ -466,7 +465,7 @@ class CoredeviceTest(ExperimentCase): rate = self.dataset_mgr.get("pulse_rate") print(rate) self.assertGreater(rate, 100*ns) - if exp.core.target_cls == CortexA9Target: + if exp.core.target == "cortexa9": # Crappy AXI PS/PL interface from Xilinx is slow. self.assertLess(rate, 810*ns) else: @@ -728,7 +727,7 @@ class DMATest(ExperimentCase): raise unittest.SkipTest("skipped on Kasli for now") exp = self.create(_DMA) - is_zynq = exp.core.target_cls == CortexA9Target + is_zynq = exp.core.target == "cortexa9" count = 20000 exp.record_many(40) exp.playback_many(count, is_zynq) From 158d65c822bb249ad3a90c9e59ce115b6f6c7746 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 18:53:12 +0800 Subject: [PATCH 101/352] test_spi: port imports to NAC3 --- artiq/test/coredevice/test_spi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_spi.py b/artiq/test/coredevice/test_spi.py index 0faf4677f..02429cf09 100644 --- a/artiq/test/coredevice/test_spi.py +++ b/artiq/test/coredevice/test_spi.py @@ -1,7 +1,7 @@ import unittest from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase -from artiq.language.core import (kernel, delay_mu, delay) +from artiq.language.core import kernel from artiq.language.units import us from artiq.coredevice import spi2 as spi From 5572f223d12f7efe3cf444188c9ef6a926b0a653 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 18:53:35 +0800 Subject: [PATCH 102/352] hardware_testbench: port imports to NAC3 --- artiq/test/hardware_testbench.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/test/hardware_testbench.py b/artiq/test/hardware_testbench.py index 987a1cf6b..4dab44833 100644 --- a/artiq/test/hardware_testbench.py +++ b/artiq/test/hardware_testbench.py @@ -6,9 +6,10 @@ import sys import unittest import logging +from nac3artiq import CompileError + from artiq.master.databases import DeviceDB, DatasetDB from artiq.master.worker_db import DeviceManager, DatasetManager, DeviceError -from artiq.coredevice.core import CompileError from artiq.frontend.artiq_run import DummyScheduler From 0266d524971397fe4c4ad2d2bc87fd903a575930 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Feb 2022 18:53:43 +0800 Subject: [PATCH 103/352] flake: re-enable basic tests --- flake.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/flake.nix b/flake.nix index 1a1c2edba..10d25b15e 100644 --- a/flake.nix +++ b/flake.nix @@ -107,7 +107,6 @@ checkPhase = '' python -m unittest discover -v artiq.test ''; - doCheck = false; # TODO }; migen = pkgs.python3Packages.buildPythonPackage rec { From bf8e188868c17c66653b1e993f2e8384b53efc08 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Feb 2022 10:22:29 +0800 Subject: [PATCH 104/352] ad9914: port to NAC3 --- artiq/coredevice/ad9914.py | 113 +++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 48 deletions(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index ce7e3b1a2..1a8abe35c 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -2,13 +2,18 @@ Driver for the AD9914 DDS (with parallel bus) on RTIO. """ +from numpy import int32, int64 from artiq.language.core import * -from artiq.language.types import * from artiq.language.units import * from artiq.coredevice.rtio import rtio_output +from artiq.coredevice.core import Core -from numpy import int32, int64 + +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass __all__ = [ @@ -43,6 +48,7 @@ AD9914_FUD = 0x80 AD9914_GPIO = 0x81 +@nac3 class AD9914: """Driver for one AD9914 DDS channel. @@ -57,10 +63,21 @@ class AD9914: :param channel: channel number (on the bus) of the DDS device to control. """ - kernel_invariants = {"core", "sysclk", "bus_channel", "channel", - "rtio_period_mu", "sysclk_per_mu", "write_duration_mu", - "dac_cal_duration_mu", "init_duration_mu", "init_sync_duration_mu", - "set_duration_mu", "set_x_duration_mu", "exit_x_duration_mu"} + core: KernelInvariant[Core] + sysclk: KernelInvariant[float] + bus_channel: KernelInvariant[int32] + channel: KernelInvariant[int32] + phase_mode: Kernel[int32] + rtio_period_mu: KernelInvariant[int64] + sysclk_per_mu: KernelInvariant[int64] + write_duration_mu: KernelInvariant[int64] + dac_cal_duration_mu: KernelInvariant[int64] + init_duration_mu: KernelInvariant[int64] + init_sync_duration_mu: KernelInvariant[int64] + set_duration_mu: KernelInvariant[int64] + set_x_duration_mu: KernelInvariant[int64] + exit_x_duration_mu: KernelInvariant[int64] + def __init__(self, dmgr, sysclk, bus_channel, channel, core_device="core"): self.core = dmgr.get(core_device) @@ -70,7 +87,7 @@ class AD9914: self.phase_mode = PHASE_MODE_CONTINUOUS self.rtio_period_mu = int64(8) - self.sysclk_per_mu = int32(self.sysclk * self.core.ref_period) + self.sysclk_per_mu = int64(self.sysclk * self.core.ref_period) self.write_duration_mu = 5 * self.rtio_period_mu self.dac_cal_duration_mu = 147000 * self.rtio_period_mu @@ -81,7 +98,7 @@ class AD9914: self.exit_x_duration_mu = 3 * self.write_duration_mu @kernel - def write(self, addr, data): + def write(self, addr: int32, data: int32): rtio_output((self.bus_channel << 8) | addr, data) delay_mu(self.write_duration_mu) @@ -113,7 +130,7 @@ class AD9914: self.write(AD9914_FUD, 0) @kernel - def init_sync(self, sync_delay): + def init_sync(self, sync_delay: int32): """Resets and initializes the DDS channel as well as configures the AD9914 DDS for synchronisation. The synchronisation procedure follows the steps outlined in the AN-1254 application note. @@ -157,7 +174,7 @@ class AD9914: self.write(AD9914_FUD, 0) @kernel - def set_phase_mode(self, phase_mode): + def set_phase_mode(self, phase_mode: int32): """Sets the phase mode of the DDS channel. Supported phase modes are: * :const:`PHASE_MODE_CONTINUOUS`: the phase accumulator is unchanged when @@ -181,8 +198,8 @@ class AD9914: self.phase_mode = phase_mode @kernel - def set_mu(self, ftw, pow=0, phase_mode=_PHASE_MODE_DEFAULT, - asf=0x0fff, ref_time_mu=-1): + def set_mu(self, ftw: int32, pow: int32 = 0, phase_mode: int32 = _PHASE_MODE_DEFAULT, + asf: int32 = 0x0fff, ref_time_mu: int64 = int64(-1)) -> int32: """Sets the DDS channel to the specified frequency and phase. This uses machine units (FTW and POW). The frequency tuning word width @@ -205,7 +222,7 @@ class AD9914: """ if phase_mode == _PHASE_MODE_DEFAULT: phase_mode = self.phase_mode - if ref_time_mu < 0: + if ref_time_mu < int64(0): ref_time_mu = now_mu() delay_mu(-self.set_duration_mu) @@ -224,60 +241,60 @@ class AD9914: # Clear phase accumulator on FUD # Enable autoclear phase accumulator and enables OSK. self.write(AD9914_REG_CFR1L, 0x2108) - fud_time = now_mu() + 2 * self.write_duration_mu - pow -= int32((ref_time_mu - fud_time) * self.sysclk_per_mu * ftw >> (32 - 16)) + fud_time = now_mu() + int64(2) * self.write_duration_mu + pow -= int32((ref_time_mu - fud_time) * self.sysclk_per_mu * int64(ftw) >> int64(32 - 16)) if phase_mode == PHASE_MODE_TRACKING: - pow += int32(ref_time_mu * self.sysclk_per_mu * ftw >> (32 - 16)) + pow += int32(ref_time_mu * self.sysclk_per_mu * int64(ftw) >> int64(32 - 16)) self.write(AD9914_REG_POW, pow) self.write(AD9914_REG_ASF, asf) self.write(AD9914_FUD, 0) return pow - @portable(flags={"fast-math"}) - def frequency_to_ftw(self, frequency): + @portable + def frequency_to_ftw(self, frequency: float) -> int32: """Returns the 32-bit frequency tuning word corresponding to the given frequency. """ - return int32(round(float(int64(2)**32*frequency/self.sysclk))) + return round(float(int64(2)**int64(32))*frequency/self.sysclk) - @portable(flags={"fast-math"}) - def ftw_to_frequency(self, ftw): + @portable + def ftw_to_frequency(self, ftw: int32) -> float: """Returns the frequency corresponding to the given frequency tuning word. """ - return ftw*self.sysclk/int64(2)**32 + return float(ftw)*self.sysclk/float(int64(2)**int64(32)) - @portable(flags={"fast-math"}) - def turns_to_pow(self, turns): + @portable + def turns_to_pow(self, turns: float) -> int32: """Returns the 16-bit phase offset word corresponding to the given phase in turns.""" - return round(float(turns*2**16)) & 0xffff + return round(float(turns*float(2**16))) & 0xffff - @portable(flags={"fast-math"}) - def pow_to_turns(self, pow): + @portable + def pow_to_turns(self, pow: int32) -> float: """Returns the phase in turns corresponding to the given phase offset word.""" - return pow/2**16 + return float(pow)/float(2**16) - @portable(flags={"fast-math"}) - def amplitude_to_asf(self, amplitude): + @portable + def amplitude_to_asf(self, amplitude: float) -> int32: """Returns 12-bit amplitude scale factor corresponding to given amplitude.""" - code = round(float(amplitude * 0x0fff)) + code = round(float(amplitude * float(0x0fff))) if code < 0 or code > 0xfff: raise ValueError("Invalid AD9914 amplitude!") return code - @portable(flags={"fast-math"}) - def asf_to_amplitude(self, asf): + @portable + def asf_to_amplitude(self, asf: int32) -> float: """Returns the amplitude corresponding to the given amplitude scale factor.""" return asf/0x0fff @kernel - def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT, - amplitude=1.0): + def set(self, frequency: float, phase: float = 0.0, phase_mode: int32 = _PHASE_MODE_DEFAULT, + amplitude: float = 1.0) -> float: """Like :meth:`set_mu`, but uses Hz and turns.""" return self.pow_to_turns( self.set_mu(self.frequency_to_ftw(frequency), @@ -286,7 +303,7 @@ class AD9914: # Extended-resolution functions @kernel - def set_x_mu(self, xftw, amplitude=0x0fff): + def set_x_mu(self, xftw: int64, amplitude: int32 = 0x0fff): """Set the DDS frequency and amplitude with an extended-resolution (63-bit) frequency tuning word. @@ -300,10 +317,10 @@ class AD9914: self.write(AD9914_GPIO, (1 << self.channel) << 1) - self.write(AD9914_REG_DRGAL, xftw & 0xffff) - self.write(AD9914_REG_DRGAH, (xftw >> 16) & 0x7fff) - self.write(AD9914_REG_DRGFL, (xftw >> 31) & 0xffff) - self.write(AD9914_REG_DRGFH, (xftw >> 47) & 0xffff) + self.write(AD9914_REG_DRGAL, int32(xftw) & 0xffff) + self.write(AD9914_REG_DRGAH, int32(xftw >> int64(16)) & 0x7fff) + self.write(AD9914_REG_DRGFL, int32(xftw >> int64(31)) & 0xffff) + self.write(AD9914_REG_DRGFH, int32(xftw >> int64(47)) & 0xffff) self.write(AD9914_REG_ASF, amplitude) self.write(AD9914_FUD, 0) @@ -316,23 +333,23 @@ class AD9914: self.write(AD9914_REG_DRGAL, 0) self.write(AD9914_REG_DRGAH, 0) - @portable(flags={"fast-math"}) - def frequency_to_xftw(self, frequency): + @portable + def frequency_to_xftw(self, frequency: float) -> int64: """Returns the 63-bit frequency tuning word corresponding to the given frequency (extended resolution mode). """ - return int64(round(2.0*float(int64(2)**62)*frequency/self.sysclk)) & ( - (int64(1) << 63) - 1) + return round64(2.0*float(int64(2)**int64(62))*frequency/self.sysclk) & ( + (int64(1) << int64(63)) - int64(1)) - @portable(flags={"fast-math"}) - def xftw_to_frequency(self, xftw): + @portable + def xftw_to_frequency(self, xftw: int64) -> float: """Returns the frequency corresponding to the given frequency tuning word (extended resolution mode). """ - return xftw*self.sysclk/(2.0*float(int64(2)**62)) + return float(xftw)*self.sysclk/(2.0*float(int64(2)**int64(62))) @kernel - def set_x(self, frequency, amplitude=1.0): + def set_x(self, frequency: float, amplitude: float = 1.0): """Like :meth:`set_x_mu`, but uses Hz and turns. Note that the precision of ``float`` is less than the precision From 2e4233274f9b09a37085fd3802d08f00db152c1c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Feb 2022 11:53:41 +0800 Subject: [PATCH 105/352] grabber: port to NAC3 --- artiq/coredevice/grabber.py | 22 ++++++++++++--------- artiq/examples/nac3devices/nac3devices.json | 4 ++++ artiq/examples/nac3devices/nac3devices.py | 3 +++ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/grabber.py b/artiq/coredevice/grabber.py index 6f29debe3..c71414a6d 100644 --- a/artiq/coredevice/grabber.py +++ b/artiq/coredevice/grabber.py @@ -1,19 +1,23 @@ from numpy import int32, int64 from artiq.language.core import * -from artiq.language.types import * from artiq.coredevice.rtio import rtio_output, rtio_input_data +from artiq.coredevice.core import Core +@nac3 class OutOfSyncException(Exception): """Raised when an incorrect number of ROI engine outputs has been retrieved from the RTIO input FIFO.""" pass +@nac3 class Grabber: """Driver for the Grabber camera interface.""" - kernel_invariants = {"core", "channel_base", "sentinel"} + core: KernelInvariant[Core] + channel_base: KernelInvariant[int32] + sentinel: KernelInvariant[int32] def __init__(self, dmgr, channel_base, res_width=12, count_shift=0, core_device="core"): @@ -26,7 +30,7 @@ class Grabber: self.sentinel = int32(int64(2**count_width)) @kernel - def setup_roi(self, n, x0, y0, x1, y1): + def setup_roi(self, n: int32, x0: int32, y0: int32, x1: int32, y1: int32): """ Defines the coordinates of a ROI. @@ -50,7 +54,7 @@ class Grabber: delay_mu(c) @kernel - def gate_roi(self, mask): + def gate_roi(self, mask: int32): """ Defines which ROI engines produce input events. @@ -70,15 +74,15 @@ class Grabber: rtio_output((self.channel_base + 1) << 8, mask) @kernel - def gate_roi_pulse(self, mask, dt): + def gate_roi_pulse(self, mask: int32, dt: float): """Sets a temporary mask for the specified duration (in seconds), before disabling all ROI engines.""" self.gate_roi(mask) - delay(dt) + self.core.delay(dt) self.gate_roi(0) @kernel - def input_mu(self, data): + def input_mu(self, data: list[int32]): """ Retrieves the accumulated values for one frame from the ROI engines. Blocks until values are available. @@ -96,10 +100,10 @@ class Grabber: sentinel = rtio_input_data(channel) if sentinel != self.sentinel: - raise OutOfSyncException + raise OutOfSyncException() for i in range(len(data)): roi_output = rtio_input_data(channel) if roi_output == self.sentinel: - raise OutOfSyncException + raise OutOfSyncException() data[i] = roi_output diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json index a376ee3af..aae7184fe 100644 --- a/artiq/examples/nac3devices/nac3devices.json +++ b/artiq/examples/nac3devices/nac3devices.json @@ -32,6 +32,10 @@ "bank_direction_low": "input", "bank_direction_high": "output", "edge_counter": true + }, + { + "type": "grabber", + "ports": [6] } ] } diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index 051e56e0f..b979bd19c 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -8,6 +8,7 @@ from artiq.coredevice.urukul import CPLD as UrukulCPLD from artiq.coredevice.ad9912 import AD9912 from artiq.coredevice.sampler import Sampler from artiq.coredevice.edge_counter import EdgeCounter +from artiq.coredevice.grabber import Grabber @nac3 @@ -21,6 +22,7 @@ class NAC3Devices(EnvExperiment): urukul0_ch0: KernelInvariant[AD9912] sampler0: KernelInvariant[Sampler] ttl0_counter: KernelInvariant[EdgeCounter] + grabber0: KernelInvariant[Grabber] def build(self): self.setattr_device("core") @@ -32,6 +34,7 @@ class NAC3Devices(EnvExperiment): self.setattr_device("urukul0_ch0") self.setattr_device("sampler0") self.setattr_device("ttl0_counter") + self.setattr_device("grabber0") @kernel def run(self): From 64a0c4b29a4f220270c9f64340d3b3b4103e7c72 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Feb 2022 12:04:46 +0800 Subject: [PATCH 106/352] merge artiq.coredevice.runtime into comm_kernel --- artiq/coredevice/comm_kernel.py | 12 +++++++++++- artiq/coredevice/runtime.py | 14 -------------- 2 files changed, 11 insertions(+), 15 deletions(-) delete mode 100644 artiq/coredevice/runtime.py diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 9e5711bf6..8bb8305d8 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -5,6 +5,7 @@ import numpy import socket import re import linecache +import os from enum import Enum from fractions import Fraction from collections import namedtuple @@ -12,7 +13,6 @@ from collections import namedtuple from artiq.coredevice import exceptions from artiq.coredevice.comm import initialize_connection from artiq import __version__ as software_version -from artiq.coredevice.runtime import source_loader from artiq import __artiq_dir__ as artiq_dir @@ -175,6 +175,16 @@ class CommKernelDummy: pass +class SourceLoader: + def __init__(self, runtime_root): + self.runtime_root = runtime_root + + def get_source(self, filename): + with open(os.path.join(self.runtime_root, filename)) as f: + return f.read() + +source_loader = SourceLoader(os.path.join(artiq_dir, "soc", "runtime")) + class CoreException: """Information about an exception raised or passed through the core device.""" diff --git a/artiq/coredevice/runtime.py b/artiq/coredevice/runtime.py deleted file mode 100644 index 4d65e86d8..000000000 --- a/artiq/coredevice/runtime.py +++ /dev/null @@ -1,14 +0,0 @@ -import os - -from artiq import __artiq_dir__ as artiq_dir - - -class SourceLoader: - def __init__(self, runtime_root): - self.runtime_root = runtime_root - - def get_source(self, filename): - with open(os.path.join(self.runtime_root, filename)) as f: - return f.read() - -source_loader = SourceLoader(os.path.join(artiq_dir, "soc", "runtime")) From a407007e0bf596a419ae4da8eec8aab7e01e058b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Feb 2022 13:34:55 +0800 Subject: [PATCH 107/352] fastino: port to NAC3 --- artiq/coredevice/fastino.py | 74 ++++++++++++--------- artiq/examples/nac3devices/nac3devices.json | 4 ++ artiq/examples/nac3devices/nac3devices.py | 3 + 3 files changed, 51 insertions(+), 30 deletions(-) diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index c2ea4ad2c..f0ab00cc2 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -3,13 +3,23 @@ streaming DAC. """ from numpy import int32, int64 -from artiq.language.core import kernel, portable, delay, delay_mu +from artiq.language.core import nac3, kernel, portable, KernelInvariant from artiq.coredevice.rtio import (rtio_output, rtio_output_wide, rtio_input_data) from artiq.language.units import ns -from artiq.language.types import TInt32, TList +from artiq.coredevice.core import Core +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass +@nac3 +class NotImplementedError(Exception): + pass + + +@nac3 class Fastino: """Fastino 32-channel, 16-bit, 2.5 MS/s per channel streaming DAC @@ -41,7 +51,11 @@ class Fastino: :param log2_width: Width of DAC channel group (logarithm base 2). Value must match the corresponding value in the RTIO PHY (gateware). """ - kernel_invariants = {"core", "channel", "width", "t_frame"} + + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + width: KernelInvariant[int32] + t_frame: KernelInvariant[int64] def __init__(self, dmgr, channel, core_device="core", log2_width=0): self.channel = channel << 8 @@ -69,15 +83,15 @@ class Fastino: Note: On Fastino gateware before v0.2 this may lead to 0 voltage being emitted transiently. """ - self.set_cfg(reset=0, afe_power_down=0, dac_clr=0, clr_err=1) + self.set_cfg(reset=False, afe_power_down=False, dac_clr=False, clr_err=True) delay_mu(self.t_frame) - self.set_cfg(reset=0, afe_power_down=0, dac_clr=0, clr_err=0) + self.set_cfg(reset=False, afe_power_down=False, dac_clr=False, clr_err=False) delay_mu(self.t_frame) self.set_continuous(0) delay_mu(self.t_frame) self.stage_cic(1) delay_mu(self.t_frame) - self.apply_cic(0xffffffff) + self.apply_cic(int32(int64(0xffffffff))) delay_mu(self.t_frame) self.set_leds(0) delay_mu(self.t_frame) @@ -85,7 +99,7 @@ class Fastino: delay_mu(self.t_frame) @kernel - def write(self, addr, data): + def write(self, addr: int32, data: int32): """Write data to a Fastino register. :param addr: Address to write to. @@ -94,7 +108,7 @@ class Fastino: rtio_output(self.channel | addr, data) @kernel - def read(self, addr): + def read(self, addr: int32): """Read from Fastino register. TODO: untested @@ -102,12 +116,12 @@ class Fastino: :param addr: Address to read from. :return: The data read. """ - raise NotImplementedError + raise NotImplementedError() # rtio_output(self.channel | addr | 0x80) # return rtio_input_data(self.channel >> 8) @kernel - def set_dac_mu(self, dac, data): + def set_dac_mu(self, dac: int32, data: int32): """Write DAC data in machine units. :param dac: DAC channel to write to (0-31). @@ -117,7 +131,7 @@ class Fastino: self.write(dac, data) @kernel - def set_group_mu(self, dac: TInt32, data: TList(TInt32)): + def set_group_mu(self, dac: int32, data: list[int32]): """Write a group of DAC channels in machine units. :param dac: First channel in DAC channel group (0-31). The `log2_width` @@ -127,24 +141,24 @@ class Fastino: If the list length is less than group size, the remaining DAC channels within the group are cleared to 0 (machine units). """ - if dac & (self.width - 1): + if dac & (self.width - 1) != 0: raise ValueError("Group index LSBs must be zero") rtio_output_wide(self.channel | dac, data) @portable - def voltage_to_mu(self, voltage): + def voltage_to_mu(self, voltage: float) -> int32: """Convert SI Volts to DAC machine units. :param voltage: Voltage in SI Volts. :return: DAC data word in machine units, 16 bit integer. """ - data = int32(round((0x8000/10.)*voltage)) + int32(0x8000) + data = int32(round((float(0x8000)/10.)*voltage)) + int32(0x8000) if data < 0 or data > 0xffff: raise ValueError("DAC voltage out of bounds") return data @portable - def voltage_group_to_mu(self, voltage, data): + def voltage_group_to_mu(self, voltage: list[float], data: list[int32]): """Convert SI Volts to packed DAC channel group machine units. :param voltage: List of SI Volt voltages. @@ -153,12 +167,12 @@ class Fastino: """ for i in range(len(voltage)): v = self.voltage_to_mu(voltage[i]) - if i & 1: + if i & 1 != 0: v = data[i // 2] | (v << 16) data[i // 2] = int32(v) @kernel - def set_dac(self, dac, voltage): + def set_dac(self, dac: int32, voltage: float): """Set DAC data to given voltage. :param dac: DAC channel (0-31). @@ -167,18 +181,18 @@ class Fastino: self.write(dac, self.voltage_to_mu(voltage)) @kernel - def set_group(self, dac, voltage): + def set_group(self, dac: int32, voltage: list[float]): """Set DAC group data to given voltage. :param dac: DAC channel (0-31). :param voltage: Desired output voltage. """ - data = [int32(0)] * (len(voltage) // 2) + data = [int32(0) for _ in range(len(voltage) // 2)] self.voltage_group_to_mu(voltage, data) self.set_group_mu(dac, data) @kernel - def update(self, update): + def update(self, update: int32): """Schedule channels for update. :param update: Bit mask of channels to update (32 bit). @@ -186,7 +200,7 @@ class Fastino: self.write(0x20, update) @kernel - def set_hold(self, hold): + def set_hold(self, hold: int32): """Set channels to manual update. :param hold: Bit mask of channels to hold (32 bit). @@ -194,7 +208,7 @@ class Fastino: self.write(0x21, hold) @kernel - def set_cfg(self, reset=0, afe_power_down=0, dac_clr=0, clr_err=0): + def set_cfg(self, reset: bool = False, afe_power_down: bool = False, dac_clr: bool = False, clr_err: bool = False): """Set configuration bits. :param reset: Reset SPI PLL and SPI clock domain. @@ -205,11 +219,11 @@ class Fastino: This clears the sticky red error LED. Must be cleared to enable error counting. """ - self.write(0x22, (reset << 0) | (afe_power_down << 1) | - (dac_clr << 2) | (clr_err << 3)) + self.write(0x22, (int32(reset) << 0) | (int32(afe_power_down) << 1) | + (int32(dac_clr) << 2) | (int32(clr_err) << 3)) @kernel - def set_leds(self, leds): + def set_leds(self, leds: int32): """Set the green user-defined LEDs :param leds: LED status, 8 bit integer each bit corresponding to one @@ -218,14 +232,14 @@ class Fastino: self.write(0x23, leds) @kernel - def set_continuous(self, channel_mask): + def set_continuous(self, channel_mask: int32): """Enable continuous DAC updates on channels regardless of new data being submitted. """ self.write(0x25, channel_mask) @kernel - def stage_cic_mu(self, rate_mantissa, rate_exponent, gain_exponent): + def stage_cic_mu(self, rate_mantissa: int32, rate_exponent: int32, gain_exponent: int32): """Stage machine unit CIC interpolator configuration. """ if rate_mantissa < 0 or rate_mantissa >= 1 << 6: @@ -238,7 +252,7 @@ class Fastino: self.write(0x26, config) @kernel - def stage_cic(self, rate) -> TInt32: + def stage_cic(self, rate: int32) -> int32: """Compute and stage interpolator configuration. This method approximates the desired interpolation rate using a 10 bit @@ -269,12 +283,12 @@ class Fastino: while gain > 1 << gain_exponent: gain_exponent += 1 gain_exponent += order*rate_exponent - assert gain_exponent <= order*16 + # NAC3TODO assert gain_exponent <= order*16 self.stage_cic_mu(rate_mantissa - 1, rate_exponent, gain_exponent) return rate_mantissa << rate_exponent @kernel - def apply_cic(self, channel_mask): + def apply_cic(self, channel_mask: int32): """Apply the staged interpolator configuration on the specified channels. Each Fastino channel starting with gateware v0.2 includes a fourth order diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json index aae7184fe..1b547d26d 100644 --- a/artiq/examples/nac3devices/nac3devices.json +++ b/artiq/examples/nac3devices/nac3devices.json @@ -36,6 +36,10 @@ { "type": "grabber", "ports": [6] + }, + { + "type": "fastino", + "ports": [7] } ] } diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index b979bd19c..ea46f72e5 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -9,6 +9,7 @@ from artiq.coredevice.ad9912 import AD9912 from artiq.coredevice.sampler import Sampler from artiq.coredevice.edge_counter import EdgeCounter from artiq.coredevice.grabber import Grabber +from artiq.coredevice.fastino import Fastino @nac3 @@ -23,6 +24,7 @@ class NAC3Devices(EnvExperiment): sampler0: KernelInvariant[Sampler] ttl0_counter: KernelInvariant[EdgeCounter] grabber0: KernelInvariant[Grabber] + fastino0: KernelInvariant[Fastino] def build(self): self.setattr_device("core") @@ -35,6 +37,7 @@ class NAC3Devices(EnvExperiment): self.setattr_device("sampler0") self.setattr_device("ttl0_counter") self.setattr_device("grabber0") + self.setattr_device("fastino0") @kernel def run(self): From ea55c29568bacddf7e2faedc5c686fe351ac5b12 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Feb 2022 17:00:24 +0800 Subject: [PATCH 108/352] phaser: port to NAC3 --- artiq/coredevice/phaser.py | 369 +++++++++++--------- artiq/examples/nac3devices/nac3devices.json | 4 + artiq/examples/nac3devices/nac3devices.py | 3 + 3 files changed, 210 insertions(+), 166 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 5f7cd7108..5f3c4c334 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -1,13 +1,28 @@ +from __future__ import annotations from numpy import int32, int64 -from artiq.language.core import kernel, delay_mu, delay +from artiq.language.core import * +from artiq.coredevice.core import Core from artiq.coredevice.rtio import rtio_output, rtio_input_data, rtio_input_timestamp from artiq.language.units import us, ns, ms, MHz -from artiq.language.types import TInt32 from artiq.coredevice.dac34h84 import DAC34H84 from artiq.coredevice.trf372017 import TRF372017 +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass + +# NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/201 +@portable +def abs(x: int32) -> int32: + if x > 0: + return x + else: + return -x + + PHASER_BOARD_ID = 19 PHASER_ADDR_BOARD_ID = 0x00 PHASER_ADDR_HW_REV = 0x01 @@ -59,6 +74,7 @@ PHASER_DAC_SEL_TEST = 1 PHASER_HW_REV_VARIANT = 1 << 4 +@nac3 class Phaser: """Phaser 4-channel, 16-bit, 1 GS/s DAC coredevice driver. @@ -133,7 +149,7 @@ class Phaser: and buffer round trip. Tuning this might be automated later. :param tune_fifo_offset: Tune the DAC FIFO read pointer offset (default=True) - :param clk_sel: Select the external SMA clock input (1 or 0) + :param clk_sel: Select the external SMA clock input. :param sync_dly: SYNC delay with respect to ISTR. :param dac: DAC34H84 DAC settings as a dictionary. :param trf0: Channel 0 TRF372017 quadrature upconverter settings as a @@ -147,11 +163,20 @@ class Phaser: To access oscillators, digital upconverters, PLL/VCO analog quadrature upconverters and attenuators. """ - kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay", - "dac_mmap"} + + core: KernelInvariant[Core] + channel_base: KernelInvariant[int32] + t_frame: KernelInvariant[int32] + miso_delay: KernelInvariant[int32] + frame_tstamp: Kernel[int64] + clk_sel: Kernel[bool] + tune_fifo_offset: Kernel[bool] + sync_dly: Kernel[int32] + dac_mmap: KernelInvariant[list[int32]] + channel: Kernel[list[PhaserChannel]] def __init__(self, dmgr, channel_base, miso_delay=1, tune_fifo_offset=True, - clk_sel=0, sync_dly=0, dac=None, trf0=None, trf1=None, + clk_sel=False, sync_dly=0, dac=None, trf0=None, trf1=None, core_device="core"): self.channel_base = channel_base self.core = dmgr.get(core_device) @@ -172,7 +197,7 @@ class Phaser: for ch, trf in enumerate([trf0, trf1])] @kernel - def init(self, debug=False): + def init(self, debug: bool = False): """Initialize the board. Verifies board and chip presence, resets components, performs @@ -182,40 +207,40 @@ class Phaser: board_id = self.read8(PHASER_ADDR_BOARD_ID) if board_id != PHASER_BOARD_ID: raise ValueError("invalid board id") - delay(.1*ms) # slack + self.core.delay(.1*ms) # slack hw_rev = self.read8(PHASER_ADDR_HW_REV) - delay(.1*ms) # slack - is_baseband = hw_rev & PHASER_HW_REV_VARIANT + self.core.delay(.1*ms) # slack + is_baseband = hw_rev & PHASER_HW_REV_VARIANT != 0 gw_rev = self.read8(PHASER_ADDR_GW_REV) if debug: - print("gw_rev:", gw_rev) + # NAC3TODO print("gw_rev:", gw_rev) self.core.break_realtime() - delay(.1*ms) # slack + self.core.delay(.1*ms) # slack # allow a few errors during startup and alignment since boot if self.get_crc_err() > 20: raise ValueError("large number of frame CRC errors") - delay(.1*ms) # slack + self.core.delay(.1*ms) # slack # determine the origin for frame-aligned timestamps self.measure_frame_timestamp() - if self.frame_tstamp < 0: + if self.frame_tstamp < int64(0): raise ValueError("frame timestamp measurement timed out") - delay(.1*ms) + self.core.delay(.1*ms) # reset - self.set_cfg(dac_resetb=0, dac_sleep=1, dac_txena=0, - trf0_ps=1, trf1_ps=1, - att0_rstn=0, att1_rstn=0) + self.set_cfg(dac_resetb=False, dac_sleep=True, dac_txena=False, + trf0_ps=True, trf1_ps=True, + att0_rstn=False, att1_rstn=False) self.set_leds(0x00) self.set_fan_mu(0) # bring dac out of reset, keep tx off - self.set_cfg(clk_sel=self.clk_sel, dac_txena=0, - trf0_ps=1, trf1_ps=1, - att0_rstn=0, att1_rstn=0) - delay(.1*ms) # slack + self.set_cfg(clk_sel=self.clk_sel, dac_txena=False, + trf0_ps=True, trf1_ps=True, + att0_rstn=False, att1_rstn=False) + self.core.delay(.1*ms) # slack # crossing dac_clk (reference) edges with sync_dly # changes the optimal fifo_offset by 4 @@ -225,25 +250,25 @@ class Phaser: self.dac_write(0x02, 0x0080) if self.dac_read(0x7f) != 0x5409: raise ValueError("DAC version readback invalid") - delay(.1*ms) + self.core.delay(.1*ms) if self.dac_read(0x00) != 0x049c: raise ValueError("DAC config0 reset readback invalid") - delay(.1*ms) + self.core.delay(.1*ms) t = self.get_dac_temperature() - delay(.1*ms) + self.core.delay(.1*ms) if t < 10 or t > 90: raise ValueError("DAC temperature out of bounds") for data in self.dac_mmap: self.dac_write(data >> 16, data) - delay(40*us) + self.core.delay(40.*us) self.dac_sync() - delay(40*us) + self.core.delay(40.*us) # pll_ndivsync_ena disable config18 = self.dac_read(0x18) - delay(.1*ms) + self.core.delay(.1*ms) self.dac_write(0x18, config18 & ~0x0800) patterns = [ @@ -256,33 +281,33 @@ class Phaser: # either side) and no need to tune at runtime. # Parity provides another level of safety. for i in range(len(patterns)): - delay(.5*ms) + self.core.delay(.5*ms) errors = self.dac_iotest(patterns[i]) - if errors: + if errors != 0: raise ValueError("DAC iotest failure") - delay(2*ms) # let it settle + self.core.delay(2.*ms) # let it settle lvolt = self.dac_read(0x18) & 7 - delay(.1*ms) + self.core.delay(.1*ms) if lvolt < 2 or lvolt > 5: raise ValueError("DAC PLL lock failed, check clocking") if self.tune_fifo_offset: fifo_offset = self.dac_tune_fifo_offset() if debug: - print("fifo_offset:", fifo_offset) + # NAC3TODO print("fifo_offset:", fifo_offset) self.core.break_realtime() # self.dac_write(0x20, 0x0000) # stop fifo sync # alarm = self.get_sta() & 1 - # delay(.1*ms) + # self.core.delay(.1*ms) self.clear_dac_alarms() - delay(2*ms) # let it run a bit + self.core.delay(2.*ms) # let it run a bit alarms = self.get_dac_alarms() - delay(.1*ms) # slack - if alarms & ~0x0040: # ignore PLL alarms (see DS) + self.core.delay(.1*ms) # slack + if alarms & ~0x0040 != 0: # ignore PLL alarms (see DS) if debug: - print("alarms:", alarms) + # NAC3TODO print("alarms:", alarms) self.core.break_realtime() # ignore alarms else: @@ -290,16 +315,16 @@ class Phaser: # avoid malformed output for: mixer_ena=1, nco_ena=0 after power up self.dac_write(self.dac_mmap[2] >> 16, self.dac_mmap[2] | (1 << 4)) - delay(40*us) + self.core.delay(40.*us) self.dac_sync() - delay(100*us) + self.core.delay(100.*us) self.dac_write(self.dac_mmap[2] >> 16, self.dac_mmap[2]) - delay(40*us) + self.core.delay(40.*us) self.dac_sync() - delay(100*us) + self.core.delay(100.*us) # power up trfs, release att reset - self.set_cfg(clk_sel=self.clk_sel, dac_txena=0) + self.set_cfg(clk_sel=self.clk_sel, dac_txena=False) for ch in range(2): channel = self.channel[ch] @@ -307,7 +332,7 @@ class Phaser: channel.set_att_mu(0x5a) if channel.get_att_mu() != 0x5a: raise ValueError("attenuator test failed") - delay(.1*ms) + self.core.delay(.1*ms) channel.set_att_mu(0x00) # minimum attenuation # test oscillators and DUC @@ -317,18 +342,18 @@ class Phaser: if i == 0: asf = 0x7fff # 6pi/4 phase - oscillator.set_amplitude_phase_mu(asf=asf, pow=0xc000, clr=1) - delay(1*us) + oscillator.set_amplitude_phase_mu(asf=asf, pow=0xc000, clr=True) + self.core.delay(1.*us) # 3pi/4 channel.set_duc_phase_mu(0x6000) - channel.set_duc_cfg(select=0, clr=1) + channel.set_duc_cfg(select=0, clr=True) self.duc_stb() - delay(.1*ms) # settle link, pipeline and impulse response + self.core.delay(.1*ms) # settle link, pipeline and impulse response data = channel.get_dac_data() - delay(1*us) + self.core.delay(1.*us) channel.oscillator[0].set_amplitude_phase_mu(asf=0, pow=0xc000, - clr=1) - delay(.1*ms) + clr=True) + self.core.delay(.1*ms) sqrt2 = 0x5a81 # 0x7fff/sqrt(2) data_i = data & 0xffff data_q = (data >> 16) & 0xffff @@ -342,27 +367,27 @@ class Phaser: if channel.trf_read(0) & 0x7f != 0x68: raise ValueError("TRF identification failed") - delay(.1*ms) + self.core.delay(.1*ms) - delay(.2*ms) + self.core.delay(.2*ms) for data in channel.trf_mmap: channel.trf_write(data) channel.cal_trf_vco() - delay(2*ms) # lock + self.core.delay(2.*ms) # lock if not (self.get_sta() & (PHASER_STA_TRF0_LD << ch)): raise ValueError("TRF lock failure") - delay(.1*ms) - if channel.trf_read(0) & 0x1000: + self.core.delay(.1*ms) + if channel.trf_read(0) & 0x1000 != 0: raise ValueError("TRF R_SAT_ERR") - delay(.1*ms) + self.core.delay(.1*ms) channel.en_trf_out() # enable dac tx self.set_cfg(clk_sel=self.clk_sel) @kernel - def write8(self, addr, data): + def write8(self, addr: int32, data: int32): """Write data to FPGA register. :param addr: Address to write to (7 bit) @@ -372,7 +397,7 @@ class Phaser: delay_mu(int64(self.t_frame)) @kernel - def read8(self, addr) -> TInt32: + def read8(self, addr: int32) -> int32: """Read from FPGA register. :param addr: Address to read from (7 bit) @@ -383,7 +408,7 @@ class Phaser: return response >> self.miso_delay @kernel - def write32(self, addr, data: TInt32): + def write32(self, addr: int32, data: int32): """Write 32 bit to a sequence of FPGA registers.""" for offset in range(4): byte = data >> 24 @@ -391,17 +416,17 @@ class Phaser: data <<= 8 @kernel - def read32(self, addr) -> TInt32: + def read32(self, addr: int32) -> int32: """Read 32 bit from a sequence of FPGA registers.""" data = 0 for offset in range(4): data <<= 8 data |= self.read8(addr + offset) - delay(20*us) # slack + self.core.delay(20.*us) # slack return data @kernel - def set_leds(self, leds): + def set_leds(self, leds: int32): """Set the front panel LEDs. :param leds: LED settings (6 bit) @@ -409,7 +434,7 @@ class Phaser: self.write8(PHASER_ADDR_LED, leds) @kernel - def set_fan_mu(self, pwm): + def set_fan_mu(self, pwm: int32): """Set the fan duty cycle. :param pwm: Duty cycle in machine units (8 bit) @@ -417,19 +442,19 @@ class Phaser: self.write8(PHASER_ADDR_FAN, pwm) @kernel - def set_fan(self, duty): + def set_fan(self, duty: float): """Set the fan duty cycle. :param duty: Duty cycle (0. to 1.) """ - pwm = int32(round(duty*255.)) + pwm = round(duty*255.) if pwm < 0 or pwm > 255: raise ValueError("duty cycle out of bounds") self.set_fan_mu(pwm) @kernel - def set_cfg(self, clk_sel=0, dac_resetb=1, dac_sleep=0, dac_txena=1, - trf0_ps=0, trf1_ps=0, att0_rstn=1, att1_rstn=1): + def set_cfg(self, clk_sel: bool = False, dac_resetb: bool = True, dac_sleep: bool = False, dac_txena: bool = True, + trf0_ps: bool = False, trf1_ps: bool = False, att0_rstn: bool = True, att1_rstn: bool = True): """Set the configuration register. Each flag is a single bit (0 or 1). @@ -444,13 +469,13 @@ class Phaser: :param att1_rstn: Active low attenuator 1 reset """ self.write8(PHASER_ADDR_CFG, - ((clk_sel & 1) << 0) | ((dac_resetb & 1) << 1) | - ((dac_sleep & 1) << 2) | ((dac_txena & 1) << 3) | - ((trf0_ps & 1) << 4) | ((trf1_ps & 1) << 5) | - ((att0_rstn & 1) << 6) | ((att1_rstn & 1) << 7)) + (int32(clk_sel) << 0) | (int32(dac_resetb) << 1) | + (int32(dac_sleep) << 2) | (int32(dac_txena) << 3) | + (int32(trf0_ps) << 4) | (int32(trf1_ps) << 5) | + (int32(att0_rstn) << 6) | (int32(att1_rstn) << 7)) @kernel - def get_sta(self): + def get_sta(self) -> int32: """Get the status register value. Bit flags are: @@ -468,7 +493,7 @@ class Phaser: return self.read8(PHASER_ADDR_STA) @kernel - def get_crc_err(self): + def get_crc_err(self) -> int32: """Get the frame CRC error counter. :return: The number of frames with CRC mismatches sind the reset of the @@ -484,21 +509,21 @@ class Phaser: See `get_next_frame_mu()`. """ rtio_output(self.channel_base << 8, 0) # read any register - self.frame_tstamp = rtio_input_timestamp(now_mu() + 4 * self.t_frame, self.channel_base) - delay(100 * us) + self.frame_tstamp = rtio_input_timestamp(now_mu() + int64(4) * int64(self.t_frame), self.channel_base) + self.core.delay(100. * us) @kernel - def get_next_frame_mu(self): + def get_next_frame_mu(self) -> int64: """Return the timestamp of the frame strictly after `now_mu()`. Register updates (DUC, DAC, TRF, etc.) scheduled at this timestamp and multiples of `self.t_frame` later will have deterministic latency to output. """ - n = int64((now_mu() - self.frame_tstamp) / self.t_frame) - return self.frame_tstamp + (n + 1) * self.t_frame + n = int64((now_mu() - self.frame_tstamp) / int64(self.t_frame)) + return self.frame_tstamp + (n + int64(1)) * int64(self.t_frame) @kernel - def set_sync_dly(self, dly): + def set_sync_dly(self, dly: int32): """Set SYNC delay. :param dly: DAC SYNC delay setting (0 to 7) @@ -517,8 +542,8 @@ class Phaser: self.write8(PHASER_ADDR_DUC_STB, 0) @kernel - def spi_cfg(self, select, div, end, clk_phase=0, clk_polarity=0, - half_duplex=0, lsb_first=0, offline=0, length=8): + def spi_cfg(self, select: int32, div: int32, end: bool, clk_phase: bool = False, clk_polarity: bool = False, + half_duplex: bool = False, lsb_first: bool = False, offline: bool = False, length: int32 = 8): """Set the SPI machine configuration :param select: Chip selects to assert (DAC, TRF0, TRF1, ATT0, ATT1) @@ -538,63 +563,63 @@ class Phaser: self.write8(PHASER_ADDR_SPI_SEL, select) self.write8(PHASER_ADDR_SPI_DIVLEN, (div - 2 >> 3) | (length - 1 << 5)) self.write8(PHASER_ADDR_SPI_CFG, - ((offline & 1) << 0) | ((end & 1) << 1) | - ((clk_phase & 1) << 2) | ((clk_polarity & 1) << 3) | - ((half_duplex & 1) << 4) | ((lsb_first & 1) << 5)) + (int32(offline) << 0) | (int32(end) << 1) | + (int32(clk_phase) << 2) | (int32(clk_polarity) << 3) | + (int32(half_duplex) << 4) | (int32(lsb_first) << 5)) @kernel - def spi_write(self, data): + def spi_write(self, data: int32): """Write 8 bits into the SPI data register and start/continue the transaction.""" self.write8(PHASER_ADDR_SPI_DATW, data) @kernel - def spi_read(self): + def spi_read(self) -> int32: """Read from the SPI input data register.""" return self.read8(PHASER_ADDR_SPI_DATR) @kernel - def dac_write(self, addr, data): + def dac_write(self, addr: int32, data: int32): """Write 16 bit to a DAC register. :param addr: Register address :param data: Register data to write """ div = 34 # 100 ns min period - t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) - self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0) + t_xfer = self.core.seconds_to_mu((8. + 1.)*float(div)*4.*ns) + self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=False) self.spi_write(addr) delay_mu(t_xfer) self.spi_write(data >> 8) delay_mu(t_xfer) - self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=1) + self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=True) self.spi_write(data) delay_mu(t_xfer) @kernel - def dac_read(self, addr, div=34) -> TInt32: + def dac_read(self, addr: int32, div: int32 = 34) -> int32: """Read from a DAC register. :param addr: Register address to read from :param div: SPI clock divider. Needs to be at least 250 (1 µs SPI clock) to read the temperature register. """ - t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) - self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0) + t_xfer = self.core.seconds_to_mu((8. + 1.)*float(div)*4.*ns) + self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=False) self.spi_write(addr | 0x80) delay_mu(t_xfer) self.spi_write(0) delay_mu(t_xfer) data = self.spi_read() << 8 - delay(20*us) # slack - self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=1) + self.core.delay(20.*us) # slack + self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=True) self.spi_write(0) delay_mu(t_xfer) data |= self.spi_read() return data @kernel - def get_dac_temperature(self) -> TInt32: + def get_dac_temperature(self) -> int32: """Read the DAC die temperature. :return: DAC temperature in degree Celsius @@ -617,12 +642,12 @@ class Phaser: .. note:: Synchronising the NCO clears the phase-accumulator """ config1f = self.dac_read(0x1f) - delay(.1*ms) + self.core.delay(.1*ms) self.dac_write(0x1f, config1f & ~int32(1 << 1)) self.dac_write(0x1f, config1f | (1 << 1)) @kernel - def set_dac_cmix(self, fs_8_step): + def set_dac_cmix(self, fs_8_step: int32): """Set the DAC coarse mixer frequency for both channels Use of the coarse mixer requires the DAC mixer to be enabled. The mixer @@ -640,11 +665,11 @@ class Phaser: vals = [0b0000, 0b1000, 0b0100, 0b1100, 0b0010, 0b1010, 0b0001, 0b1110] cmix = vals[fs_8_step%8] config0d = self.dac_read(0x0d) - delay(.1*ms) + self.core.delay(.1*ms) self.dac_write(0x0d, (config0d & ~(0b1111 << 12)) | (cmix << 12)) @kernel - def get_dac_alarms(self): + def get_dac_alarms(self) -> int32: """Read the DAC alarm flags. :return: DAC alarm flags (see datasheet for bit meaning) @@ -657,7 +682,7 @@ class Phaser: self.dac_write(0x05, 0x0000) @kernel - def dac_iotest(self, pattern) -> TInt32: + def dac_iotest(self, pattern: list[int32]) -> int32: """Performs a DAC IO test according to the datasheet. :param pattern: List of four int32 containing the pattern @@ -669,7 +694,7 @@ class Phaser: self.dac_write(0x25 + addr, pattern[addr]) # repeat the pattern twice self.dac_write(0x29 + addr, pattern[addr]) - delay(.1*ms) + self.core.delay(.1*ms) for ch in range(2): channel = self.channel[ch] channel.set_duc_cfg(select=1) # test @@ -678,20 +703,20 @@ class Phaser: channel.set_dac_test(data) if channel.get_dac_data() != data: raise ValueError("DAC test data readback failed") - delay(.1*ms) + self.core.delay(.1*ms) cfg = self.dac_read(0x01) - delay(.1*ms) + self.core.delay(.1*ms) self.dac_write(0x01, cfg | 0x8000) # iotest_ena self.dac_write(0x04, 0x0000) # clear iotest_result - delay(.2*ms) # let it rip + self.core.delay(.2*ms) # let it rip # no need to go through the alarm register, # just read the error mask # self.clear_dac_alarms() alarms = self.get_dac_alarms() - delay(.1*ms) # slack - if alarms & 0x0080: # alarm_from_iotest + self.core.delay(.1*ms) # slack + if alarms & 0x0080 != 0: # alarm_from_iotest errors = self.dac_read(0x04) - delay(.1*ms) # slack + self.core.delay(.1*ms) # slack else: errors = 0 self.dac_write(0x01, cfg) # clear config @@ -699,7 +724,7 @@ class Phaser: return errors @kernel - def dac_tune_fifo_offset(self): + def dac_tune_fifo_offset(self) -> int32: """Scan through `fifo_offset` and configure midpoint setting. :return: Optimal `fifo_offset` setting with maximum margin to write @@ -712,15 +737,15 @@ class Phaser: # distance 32101234 # error free x xx config9 = self.dac_read(0x09) - delay(.1*ms) + self.core.delay(.1*ms) good = 0 for o in range(8): # set new fifo_offset self.dac_write(0x09, (config9 & 0x1fff) | (o << 13)) self.clear_dac_alarms() - delay(.1*ms) # run + self.core.delay(.1*ms) # run alarms = self.get_dac_alarms() - delay(.1*ms) # slack + self.core.delay(.1*ms) # slack if (alarms >> 11) & 0x7 == 0: # any fifo alarm good |= 1 << o # if there are good offsets accross the wrap around @@ -734,7 +759,7 @@ class Phaser: sum = 0 count = 0 for o in range(8): - if good & (1 << o): + if good & (1 << o) != 0: sum += o count += 1 best = ((sum // count) + offset) % 8 @@ -742,6 +767,7 @@ class Phaser: return best +@nac3 class PhaserChannel: """Phaser channel IQ pair. @@ -772,9 +798,15 @@ class PhaserChannel: or overflow after the interpolation. Either band-limit any changes in the oscillator parameters or back off the amplitude sufficiently. """ - kernel_invariants = {"index", "phaser", "trf_mmap"} + + core: KernelInvariant[Core] + phaser: KernelInvariant[Phaser] + index: KernelInvariant[int32] + trf_mmap: KernelInvariant[list[int32]] + oscillator: Kernel[list[PhaserOscillator]] def __init__(self, phaser, index, trf): + self.core = phaser.core self.phaser = phaser self.index = index self.trf_mmap = TRF372017(trf).get_mmap() @@ -782,7 +814,7 @@ class PhaserChannel: self.oscillator = [PhaserOscillator(self, osc) for osc in range(5)] @kernel - def get_dac_data(self) -> TInt32: + def get_dac_data(self) -> int32: """Get a sample of the current DAC data. The data is split accross multiple registers and thus the data @@ -794,7 +826,7 @@ class PhaserChannel: return self.phaser.read32(PHASER_ADDR_DAC0_DATA + (self.index << 4)) @kernel - def set_dac_test(self, data: TInt32): + def set_dac_test(self, data: int32): """Set the DAC test data. :param data: 32 bit IQ test data, I/DACA/DACC in the 16 LSB, @@ -803,7 +835,7 @@ class PhaserChannel: self.phaser.write32(PHASER_ADDR_DAC0_TEST + (self.index << 4), data) @kernel - def set_duc_cfg(self, clr=0, clr_once=0, select=0): + def set_duc_cfg(self, clr: bool = False, clr_once: bool = False, select: int32 = 0): """Set the digital upconverter (DUC) and interpolator configuration. :param clr: Keep the phase accumulator cleared (persistent) @@ -812,11 +844,11 @@ class PhaserChannel: data, other values: reserved) """ self.phaser.write8(PHASER_ADDR_DUC0_CFG + (self.index << 4), - ((clr & 1) << 0) | ((clr_once & 1) << 1) | + (int32(clr) << 0) | (int32(clr_once) << 1) | ((select & 3) << 2)) @kernel - def set_duc_frequency_mu(self, ftw): + def set_duc_frequency_mu(self, ftw: int32): """Set the DUC frequency. :param ftw: DUC frequency tuning word (32 bit) @@ -824,17 +856,17 @@ class PhaserChannel: self.phaser.write32(PHASER_ADDR_DUC0_F + (self.index << 4), ftw) @kernel - def set_duc_frequency(self, frequency): + def set_duc_frequency(self, frequency: float): """Set the DUC frequency in SI units. :param frequency: DUC frequency in Hz (passband from -200 MHz to 200 MHz, wrapping around at +- 250 MHz) """ - ftw = int32(round(frequency*((1 << 30)/(125*MHz)))) + ftw = round(frequency*(float(1 << 30)/(125.*MHz))) self.set_duc_frequency_mu(ftw) @kernel - def set_duc_phase_mu(self, pow): + def set_duc_phase_mu(self, pow: int32): """Set the DUC phase offset. :param pow: DUC phase offset word (16 bit) @@ -844,16 +876,16 @@ class PhaserChannel: self.phaser.write8(addr + 1, pow) @kernel - def set_duc_phase(self, phase): + def set_duc_phase(self, phase: float): """Set the DUC phase in SI units. :param phase: DUC phase in turns """ - pow = int32(round(phase*(1 << 16))) + pow = round(phase*float(1 << 16)) self.set_duc_phase_mu(pow) @kernel - def set_nco_frequency_mu(self, ftw): + def set_nco_frequency_mu(self, ftw: int32): """Set the NCO frequency. This method stages the new NCO frequency, but does not apply it. @@ -868,7 +900,7 @@ class PhaserChannel: self.phaser.dac_write(0x14 + (self.index << 1), ftw) @kernel - def set_nco_frequency(self, frequency): + def set_nco_frequency(self, frequency: float): """Set the NCO frequency in SI units. This method stages the new NCO frequency, but does not apply it. @@ -880,11 +912,11 @@ class PhaserChannel: :param frequency: NCO frequency in Hz (passband from -400 MHz to 400 MHz, wrapping around at +- 500 MHz) """ - ftw = int32(round(frequency*((1 << 30)/(250*MHz)))) + ftw = round(frequency*(float(1 << 30)/(250.*MHz))) self.set_nco_frequency_mu(ftw) @kernel - def set_nco_phase_mu(self, pow): + def set_nco_phase_mu(self, pow: int32): """Set the NCO phase offset. By default, the new NCO phase applies on completion of the SPI @@ -902,7 +934,7 @@ class PhaserChannel: self.phaser.dac_write(0x12 + self.index, pow) @kernel - def set_nco_phase(self, phase): + def set_nco_phase(self, phase: float): """Set the NCO phase in SI units. By default, the new NCO phase applies on completion of the SPI @@ -917,36 +949,36 @@ class PhaserChannel: :param phase: NCO phase in turns """ - pow = int32(round(phase*(1 << 16))) + pow = round(phase*float(1 << 16)) self.set_nco_phase_mu(pow) @kernel - def set_att_mu(self, data): + def set_att_mu(self, data: int32): """Set channel attenuation. :param data: Attenuator data in machine units (8 bit) """ div = 34 # 30 ns min period - t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns) + t_xfer = self.core.seconds_to_mu((8. + 1.)*float(div)*4.*ns) self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.index, div=div, - end=1) + end=True) self.phaser.spi_write(data) delay_mu(t_xfer) @kernel - def set_att(self, att): + def set_att(self, att: float): """Set channel attenuation in SI units. :param att: Attenuation in dB """ # 2 lsb are inactive, resulting in 8 LSB per dB - data = 0xff - int32(round(att*8)) + data = 0xff - round(att*8.) if data < 0 or data > 0xff: raise ValueError("attenuation out of bounds") self.set_att_mu(data) @kernel - def get_att_mu(self) -> TInt32: + def get_att_mu(self) -> int32: """Read current attenuation. The current attenuation value is read without side effects. @@ -954,39 +986,39 @@ class PhaserChannel: :return: Current attenuation in machine units """ div = 34 - t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns) + t_xfer = self.core.seconds_to_mu((8. + 1.)*float(div)*4.*ns) self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.index, div=div, - end=0) + end=False) self.phaser.spi_write(0) delay_mu(t_xfer) data = self.phaser.spi_read() - delay(20*us) # slack + self.core.delay(20.*us) # slack self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.index, div=div, - end=1) + end=True) self.phaser.spi_write(data) delay_mu(t_xfer) return data @kernel - def trf_write(self, data, readback=False): + def trf_write(self, data: int32, readback: bool = False) -> int32: """Write 32 bits to quadrature upconverter register. :param data: Register data (32 bit) containing encoded address :param readback: Whether to return the read back MISO data """ div = 34 # 50 ns min period - t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns) + t_xfer = self.core.seconds_to_mu((8. + 1.)*float(div)*4.*ns) read = 0 - end = 0 - clk_phase = 0 + end = False + clk_phase = False if readback: - clk_phase = 1 + clk_phase = True for i in range(4): if i == 0 or i == 3: if i == 3: - end = 1 + end = True self.phaser.spi_cfg(select=PHASER_SEL_TRF0 << self.index, - div=div, lsb_first=1, clk_phase=clk_phase, + div=div, lsb_first=True, clk_phase=clk_phase, end=end) self.phaser.spi_write(data) data >>= 8 @@ -994,22 +1026,22 @@ class PhaserChannel: if readback: read >>= 8 read |= self.phaser.spi_read() << 24 - delay(20*us) # slack + self.core.delay(20.*us) # slack return read @kernel - def trf_read(self, addr, cnt_mux_sel=0) -> TInt32: + def trf_read(self, addr: int32, cnt_mux_sel: int32 = 0) -> int32: """Quadrature upconverter register read. :param addr: Register address to read (0 to 7) :param cnt_mux_sel: Report VCO counter min or max frequency :return: Register data (32 bit) """ - self.trf_write(0x80000008 | (addr << 28) | (cnt_mux_sel << 27)) + self.trf_write(int32(int64(0x80000008)) | (addr << 28) | (cnt_mux_sel << 27)) # single clk pulse with ~LE to start readback - self.phaser.spi_cfg(select=0, div=34, end=1, length=1) + self.phaser.spi_cfg(select=0, div=34, end=True, length=1) self.phaser.spi_write(0) - delay((1 + 1)*34*4*ns) + self.core.delay((1. + 1.)*34.*4.*ns) return self.trf_write(0x00000008 | (cnt_mux_sel << 27), readback=True) @@ -1022,24 +1054,25 @@ class PhaserChannel: self.trf_write(self.trf_mmap[1] | (1 << 31)) @kernel - def en_trf_out(self, rf=1, lo=0): + def en_trf_out(self, rf: bool = True, lo: bool = False): """Enable the rf/lo outputs of the upconverter (hardware variant). :param rf: 1 to enable RF output, 0 to disable :param lo: 1 to enable LO output, 0 to disable """ data = self.trf_read(0xc) - delay(0.1 * ms) + self.core.delay(0.1 * ms) # set RF and LO output bits data = data | (1 << 12) | (1 << 13) | (1 << 14) # clear to enable output - if rf == 1: + if rf: data = data ^ (1 << 14) - if lo == 1: + if lo: data = data ^ ((1 << 12) | (1 << 13)) self.trf_write(data) +@nac3 class PhaserOscillator: """Phaser IQ channel oscillator (NCO/DDS). @@ -1047,15 +1080,19 @@ class PhaserOscillator: oscillator parameters (amplitude and phase/frequency) are deterministic (with respect to the 25 MS/s sample clock) but not matched. """ - kernel_invariants = {"channel", "base_addr"} + + core: KernelInvariant[Core] + channel: KernelInvariant[PhaserChannel] + base_addr: KernelInvariant[int32] def __init__(self, channel, index): + self.core = channel.core self.channel = channel self.base_addr = ((self.channel.phaser.channel_base + 1 + 2*self.channel.index) << 8) | index @kernel - def set_frequency_mu(self, ftw): + def set_frequency_mu(self, ftw: int32): """Set Phaser MultiDDS frequency tuning word. :param ftw: Frequency tuning word (32 bit) @@ -1063,36 +1100,36 @@ class PhaserOscillator: rtio_output(self.base_addr, ftw) @kernel - def set_frequency(self, frequency): + def set_frequency(self, frequency: float): """Set Phaser MultiDDS frequency. :param frequency: Frequency in Hz (passband from -10 MHz to 10 MHz, wrapping around at +- 12.5 MHz) """ - ftw = int32(round(frequency*((1 << 30)/(6.25*MHz)))) + ftw = round(frequency*(float(1 << 30)/(6.25*MHz))) self.set_frequency_mu(ftw) @kernel - def set_amplitude_phase_mu(self, asf=0x7fff, pow=0, clr=0): + def set_amplitude_phase_mu(self, asf: int32 = 0x7fff, pow: int32 = 0, clr: bool = False): """Set Phaser MultiDDS amplitude, phase offset and accumulator clear. :param asf: Amplitude (15 bit) :param pow: Phase offset word (16 bit) :param clr: Clear the phase accumulator (persistent) """ - data = (asf & 0x7fff) | ((clr & 1) << 15) | (pow << 16) + data = (asf & 0x7fff) | (int32(clr) << 15) | (pow << 16) rtio_output(self.base_addr + (1 << 8), data) @kernel - def set_amplitude_phase(self, amplitude, phase=0., clr=0): + def set_amplitude_phase(self, amplitude: float, phase: float = 0., clr: bool = False): """Set Phaser MultiDDS amplitude and phase. :param amplitude: Amplitude in units of full scale :param phase: Phase in turns :param clr: Clear the phase accumulator (persistent) """ - asf = int32(round(amplitude*0x7fff)) + asf = round(amplitude*float(0x7fff)) if asf < 0 or asf > 0x7fff: raise ValueError("amplitude out of bounds") - pow = int32(round(phase*(1 << 16))) + pow = round(phase*float(1 << 16)) self.set_amplitude_phase_mu(asf, pow, clr) diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json index 1b547d26d..45c946d3e 100644 --- a/artiq/examples/nac3devices/nac3devices.json +++ b/artiq/examples/nac3devices/nac3devices.json @@ -40,6 +40,10 @@ { "type": "fastino", "ports": [7] + }, + { + "type": "phaser", + "ports": [8] } ] } diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index ea46f72e5..396da3fd5 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -10,6 +10,7 @@ from artiq.coredevice.sampler import Sampler from artiq.coredevice.edge_counter import EdgeCounter from artiq.coredevice.grabber import Grabber from artiq.coredevice.fastino import Fastino +from artiq.coredevice.phaser import Phaser @nac3 @@ -25,6 +26,7 @@ class NAC3Devices(EnvExperiment): ttl0_counter: KernelInvariant[EdgeCounter] grabber0: KernelInvariant[Grabber] fastino0: KernelInvariant[Fastino] + # NAC3TODO segfault phaser0: KernelInvariant[Fastino] def build(self): self.setattr_device("core") @@ -38,6 +40,7 @@ class NAC3Devices(EnvExperiment): self.setattr_device("ttl0_counter") self.setattr_device("grabber0") self.setattr_device("fastino0") + # NAC3TODO segfault self.setattr_device("phaser0") @kernel def run(self): From b66cce14fb0f3ca31f44a10429ae6c29a5cb8599 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Mar 2022 11:48:43 +0800 Subject: [PATCH 109/352] update NAC3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index e00dff082..1018b5cbe 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1645867753, - "narHash": "sha256-BzQjd5KhQ2Lt9NPmb5cJaggjRiCA+GfeCFIIyyZp/FM=", + "lastModified": 1646061005, + "narHash": "sha256-sofIwwD5lGKzDLClfRITRyeG2mIa0Gvh55XtrWtK8/I=", "ref": "master", - "rev": "804d5db27e36da8ca6a046f20a43130d1cfe6e1e", - "revCount": 612, + "rev": "d1e172501d8ee745afcf9610516b0993cb9ff410", + "revCount": 617, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 5af22af5f65fb7f9c17159e2f3ffb5a35db2b3df Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Mar 2022 11:49:03 +0800 Subject: [PATCH 110/352] examples/nac3devices: fix and reenable Phaser --- artiq/coredevice/phaser.py | 2 ++ artiq/examples/nac3devices/nac3devices.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 5f3c4c334..a68b5eda8 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -192,6 +192,7 @@ class Phaser: self.sync_dly = sync_dly self.dac_mmap = DAC34H84(dac).get_mmap() + self.dac_mmap = [int32(x) for x in self.dac_mmap] # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/14 self.channel = [PhaserChannel(self, ch, trf) for ch, trf in enumerate([trf0, trf1])] @@ -810,6 +811,7 @@ class PhaserChannel: self.phaser = phaser self.index = index self.trf_mmap = TRF372017(trf).get_mmap() + self.trf_mmap = [int32(x) for x in self.trf_mmap] # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/14 self.oscillator = [PhaserOscillator(self, osc) for osc in range(5)] diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index 396da3fd5..79b4815fb 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -26,7 +26,7 @@ class NAC3Devices(EnvExperiment): ttl0_counter: KernelInvariant[EdgeCounter] grabber0: KernelInvariant[Grabber] fastino0: KernelInvariant[Fastino] - # NAC3TODO segfault phaser0: KernelInvariant[Fastino] + phaser0: KernelInvariant[Phaser] def build(self): self.setattr_device("core") @@ -40,7 +40,7 @@ class NAC3Devices(EnvExperiment): self.setattr_device("ttl0_counter") self.setattr_device("grabber0") self.setattr_device("fastino0") - # NAC3TODO segfault self.setattr_device("phaser0") + self.setattr_device("phaser0") @kernel def run(self): From 01e55f573105ce52d3bfdb03723f699170e1d672 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Mar 2022 17:21:54 +0800 Subject: [PATCH 111/352] i2c: port to NAC3 --- artiq/coredevice/i2c.py | 47 +++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/artiq/coredevice/i2c.py b/artiq/coredevice/i2c.py index 71bed00be..db5427d1c 100644 --- a/artiq/coredevice/i2c.py +++ b/artiq/coredevice/i2c.py @@ -3,8 +3,10 @@ Non-realtime drivers for I2C chips on the core device. """ from numpy import int32 -from artiq.language.core import extern, kernel + +from artiq.language.core import nac3, extern, kernel, KernelInvariant from artiq.coredevice.exceptions import I2CError +from artiq.coredevice.core import Core @extern @@ -32,13 +34,13 @@ def i2c_read(busno: int32, ack: bool) -> int32: raise NotImplementedError("syscall not simulated") -@syscall(flags={"nounwind", "nowrite"}) -def i2c_switch_select(busno: TInt32, address: TInt32, mask: TInt32) -> TNone: +@extern +def i2c_switch_select(busno: int32, address: int32, mask: int32): raise NotImplementedError("syscall not simulated") @kernel -def i2c_poll(busno, busaddr): +def i2c_poll(busno: int32, busaddr: int32) -> bool: """Poll I2C device at address. :param busno: I2C bus number @@ -52,7 +54,7 @@ def i2c_poll(busno, busaddr): @kernel -def i2c_write_byte(busno, busaddr, data, ack=True): +def i2c_write_byte(busno: int32, busaddr: int32, data: int32, ack: bool = True): """Write one byte to a device. :param busno: I2C bus number @@ -71,7 +73,7 @@ def i2c_write_byte(busno, busaddr, data, ack=True): @kernel -def i2c_read_byte(busno, busaddr): +def i2c_read_byte(busno: int32, busaddr: int32) -> int32: """Read one byte from a device. :param busno: I2C bus number @@ -90,7 +92,7 @@ def i2c_read_byte(busno, busaddr): @kernel -def i2c_write_many(busno, busaddr, addr, data, ack_last=True): +def i2c_write_many(busno: int32, busaddr: int32, addr: int32, data: list[int32], ack_last: bool = True): """Transfer multiple bytes to a device. :param busno: I2c bus number @@ -116,7 +118,7 @@ def i2c_write_many(busno, busaddr, addr, data, ack_last=True): @kernel -def i2c_read_many(busno, busaddr, addr, data): +def i2c_read_many(busno: int32, busaddr: int32, addr: int32, data: list[int32]): """Transfer multiple bytes from a device. :param busno: I2c bus number @@ -141,6 +143,7 @@ def i2c_read_many(busno, busaddr, addr, data): i2c_stop(busno) +@nac3 class I2CSwitch: """Driver for the I2C bus switch. @@ -152,13 +155,18 @@ class I2CSwitch: On the KC705, this chip is used for selecting the I2C buses on the two FMC connectors. HPC=1, LPC=2. """ + + core: KernelInvariant[Core] + busno: KernelInvariant[int32] + address: KernelInvariant[int32] + def __init__(self, dmgr, busno=0, address=0xe8, core_device="core"): self.core = dmgr.get(core_device) self.busno = busno self.address = address @kernel - def set(self, channel): + def set(self, channel: int32): """Enable one channel. :param channel: channel number (0-7) """ @@ -171,6 +179,7 @@ class I2CSwitch: i2c_switch_select(self.busno, self.address >> 1, 0) +@kernel class TCA6424A: """Driver for the TCA6424A I2C I/O expander. @@ -179,18 +188,23 @@ class TCA6424A: On the NIST QC2 hardware, this chip is used for switching the directions of TTL buffers.""" + + core: KernelInvariant[Core] + busno: KernelInvariant[int32] + address: KernelInvariant[int32] + def __init__(self, dmgr, busno=0, address=0x44, core_device="core"): self.core = dmgr.get(core_device) self.busno = busno self.address = address @kernel - def _write24(self, addr, value): + def _write24(self, addr: int32, value: int32): i2c_write_many(self.busno, self.address, addr, [value >> 16, value >> 8, value]) @kernel - def set(self, outputs): + def set(self, outputs: int32): """Drive all pins of the chip to the levels given by the specified 24-bit word. @@ -207,19 +221,26 @@ class TCA6424A: self._write24(0x8c, 0) # set all directions to output self._write24(0x84, outputs_le) # set levels + +@nac3 class PCF8574A: """Driver for the PCF8574 I2C remote 8-bit I/O expander. I2C transactions not real-time, and are performed by the CPU without involving RTIO. """ + + core: KernelInvariant[Core] + busno: KernelInvariant[int32] + address: KernelInvariant[int32] + def __init__(self, dmgr, busno=0, address=0x7c, core_device="core"): self.core = dmgr.get(core_device) self.busno = busno self.address = address @kernel - def set(self, data): + def set(self, data: int32): """Drive data on the quasi-bidirectional pins. :param data: Pin data. High bits are weakly driven high @@ -235,7 +256,7 @@ class PCF8574A: i2c_stop(self.busno) @kernel - def get(self): + def get(self) -> int32: """Retrieve quasi-bidirectional pin input data. :return: Pin data From fb0b806f61d8f901bdf70c041863b178de7d655b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Mar 2022 17:22:06 +0800 Subject: [PATCH 112/352] kasli_i2c: port to NAC3 --- artiq/coredevice/kasli_i2c.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/kasli_i2c.py b/artiq/coredevice/kasli_i2c.py index 1e031fa2b..8485811d2 100644 --- a/artiq/coredevice/kasli_i2c.py +++ b/artiq/coredevice/kasli_i2c.py @@ -1,7 +1,8 @@ from numpy import int32 from artiq.experiment import * -from artiq.coredevice.i2c import i2c_write_many, i2c_read_many, i2c_poll +from artiq.coredevice.core import Core +from artiq.coredevice.i2c import I2CSwitch, i2c_write_many, i2c_read_many, i2c_poll port_mapping = { @@ -24,7 +25,15 @@ port_mapping = { } +@nac3 class KasliEEPROM: + core: KernelInvariant[Core] + sw0: KernelInvariant[I2CSwitch] + sw1: KernelInvariant[I2CSwitch] + busno: KernelInvariant[int32] + port: KernelInvariant[int32] + address: KernelInvariant[int32] + def __init__(self, dmgr, port, busno=0, core_device="core", sw0_device="i2c_switch0", sw1_device="i2c_switch1"): self.core = dmgr.get(core_device) @@ -50,10 +59,10 @@ class KasliEEPROM: self.sw1.unset() @kernel - def write_i32(self, addr, value): + def write_i32(self, addr: int32, value: int32): self.select() try: - data = [0]*4 + data = [0 for _ in range(4)] for i in range(4): data[i] = (value >> 24) & 0xff value <<= 8 @@ -63,12 +72,12 @@ class KasliEEPROM: self.deselect() @kernel - def read_i32(self, addr): + def read_i32(self, addr: int32) -> int32: self.select() + value = int32(0) try: - data = [0]*4 + data = [0 for _ in range(4)] i2c_read_many(self.busno, self.address, addr, data) - value = int32(0) for i in range(4): value <<= 8 value |= data[i] From 156cf42f768304894161c4df577f61b008809be4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Mar 2022 17:22:19 +0800 Subject: [PATCH 113/352] nac3devices: compile KasliEEPROM --- artiq/examples/nac3devices/nac3devices.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index 79b4815fb..4cf5180b1 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -1,6 +1,7 @@ from artiq.experiment import * from artiq.coredevice.core import Core from artiq.coredevice.cache import CoreCache +from artiq.coredevice.kasli_i2c import KasliEEPROM from artiq.coredevice.zotino import Zotino from artiq.coredevice.mirny import Mirny as MirnyCPLD from artiq.coredevice.adf5356 import ADF5356 @@ -21,6 +22,7 @@ class NAC3Devices(EnvExperiment): mirny0_cpld: KernelInvariant[MirnyCPLD] mirny0_ch0: KernelInvariant[ADF5356] urukul0_cpld: KernelInvariant[UrukulCPLD] + eeprom_urukul0: KernelInvariant[KasliEEPROM] urukul0_ch0: KernelInvariant[AD9912] sampler0: KernelInvariant[Sampler] ttl0_counter: KernelInvariant[EdgeCounter] @@ -35,6 +37,7 @@ class NAC3Devices(EnvExperiment): self.setattr_device("mirny0_cpld") self.setattr_device("mirny0_ch0") self.setattr_device("urukul0_cpld") + self.setattr_device("eeprom_urukul0") self.setattr_device("urukul0_ch0") self.setattr_device("sampler0") self.setattr_device("ttl0_counter") From a3b55b61647b30552c7de140776b82ffcdb87fee Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Mar 2022 17:44:48 +0800 Subject: [PATCH 114/352] dma: tentative port to NAC3 will not work due to missing context manager and possibly memory management issues --- artiq/coredevice/dma.py | 52 ++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/artiq/coredevice/dma.py b/artiq/coredevice/dma.py index 261a6bcfe..76f1ab468 100644 --- a/artiq/coredevice/dma.py +++ b/artiq/coredevice/dma.py @@ -5,34 +5,36 @@ the core device's SDRAM, and playing them back at higher speeds than the CPU alone could achieve. """ -from artiq.language.core import syscall, kernel -from artiq.language.types import TInt32, TInt64, TStr, TNone, TTuple +from numpy import int32, int64 + +from artiq.language.core import nac3, extern, kernel, Kernel, KernelInvariant from artiq.coredevice.exceptions import DMAError - -from numpy import int64 +from artiq.coredevice.core import Core -@syscall -def dma_record_start(name: TStr) -> TNone: + +@extern +def dma_record_start(name: str): raise NotImplementedError("syscall not simulated") -@syscall -def dma_record_stop(duration: TInt64) -> TNone: +@extern +def dma_record_stop(duration: int64): raise NotImplementedError("syscall not simulated") -@syscall -def dma_erase(name: TStr) -> TNone: +@extern +def dma_erase(name: str): raise NotImplementedError("syscall not simulated") -@syscall -def dma_retrieve(name: TStr) -> TTuple([TInt64, TInt32]): +@extern +def dma_retrieve(name: str) -> tuple[int64, int32]: raise NotImplementedError("syscall not simulated") -@syscall -def dma_playback(timestamp: TInt64, ptr: TInt32) -> TNone: +@extern +def dma_playback(timestamp: int64, ptr: int32): raise NotImplementedError("syscall not simulated") +@nac3 class DMARecordContextManager: """Context manager returned by :meth:`CoreDMA.record()`. @@ -44,6 +46,9 @@ class DMARecordContextManager: are stored in a newly created trace, and ``now`` is restored to the value it had before the context manager was entered. """ + name: Kernel[str] + saved_now_mu: Kernel[int64] + def __init__(self): self.name = "" self.saved_now_mu = int64(0) @@ -52,21 +57,24 @@ class DMARecordContextManager: def __enter__(self): dma_record_start(self.name) # this may raise, so do it before altering now self.saved_now_mu = now_mu() - at_mu(0) + at_mu(int64(0)) @kernel - def __exit__(self, type, value, traceback): + def __exit__(self): dma_record_stop(now_mu()) # see above at_mu(self.saved_now_mu) +@nac3 class CoreDMA: """Core device Direct Memory Access (DMA) driver. Gives access to the DMA functionality of the core device. """ - kernel_invariants = {"core", "recorder"} + core: KernelInvariant[Core] + recorder: KernelInvariant[DMARecordContextManager] + epoch: Kernel[int32] def __init__(self, dmgr, core_device="core"): self.core = dmgr.get(core_device) @@ -74,7 +82,7 @@ class CoreDMA: self.epoch = 0 @kernel - def record(self, name): + def record(self, name: str) -> DMARecordContextManager: """Returns a context manager that will record a DMA trace called ``name``. Any previously recorded trace with the same name is overwritten. The trace will persist across kernel switches.""" @@ -83,13 +91,13 @@ class CoreDMA: return self.recorder @kernel - def erase(self, name): + def erase(self, name: str): """Removes the DMA trace with the given name from storage.""" self.epoch += 1 dma_erase(name) @kernel - def playback(self, name): + def playback(self, name: str): """Replays a previously recorded DMA trace. This function blocks until the entire trace is submitted to the RTIO FIFOs.""" (advance_mu, ptr) = dma_retrieve(name) @@ -97,14 +105,14 @@ class CoreDMA: delay_mu(advance_mu) @kernel - def get_handle(self, name): + def get_handle(self, name: str) -> tuple[int32, int64, int32]: """Returns a handle to a previously recorded DMA trace. The returned handle is only valid until the next call to :meth:`record` or :meth:`erase`.""" (advance_mu, ptr) = dma_retrieve(name) return (self.epoch, advance_mu, ptr) @kernel - def playback_handle(self, handle): + def playback_handle(self, handle: tuple[int32, int64, int32]): """Replays a handle obtained with :meth:`get_handle`. Using this function is much faster than :meth:`playback` for replaying a set of traces repeatedly, but incurs the overhead of managing the handles onto the programmer.""" From 0256c91d53185a2111654ac1aef9bbe760cb8d19 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Mar 2022 18:09:41 +0800 Subject: [PATCH 115/352] ad9912: add missing NAC3TODO --- artiq/coredevice/ad9912.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 317670e52..d8dce22e1 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -52,6 +52,7 @@ class AD9912: self.chip_select = chip_select if sw_device: self.sw = dmgr.get(sw_device) + # NAC3TODO: support no sw self.pll_n = pll_n sysclk = self.cpld.refclk / [1, 1, 2, 4][self.cpld.clk_div] * pll_n assert sysclk <= 1e9 From be07481eb5e13819bfd026d3e4926d4c0d98abe5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Mar 2022 18:48:26 +0800 Subject: [PATCH 116/352] ad9910: port to NAC3 --- artiq/coredevice/ad9910.py | 230 ++++++++++++-------- artiq/examples/nac3devices/nac3devices.json | 16 +- artiq/examples/nac3devices/nac3devices.py | 5 + 3 files changed, 155 insertions(+), 96 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index dd95114b0..1d21d8686 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -1,15 +1,35 @@ from numpy import int32, int64 -from artiq.language.core import kernel, portable +from artiq.language.core import * from artiq.language.units import us, ms -from artiq.coredevice import spi2 as spi -from artiq.coredevice import urukul -from artiq.coredevice.urukul import DEFAULT_PROFILE +from artiq.coredevice.spi2 import * +from artiq.coredevice.urukul import * +from artiq.coredevice.urukul import * +from artiq.coredevice.ttl import TTLOut +from artiq.coredevice.kasli_i2c import KasliEEPROM # NAC3TODO + + +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass + +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/206 +@portable +def min(a: int32, b: int32) -> int32: + if a > b: + return b + else: + return a + +@portable +def max(a: int32, b: int32) -> int32: + if a > b: + return a + else: + return b -# Work around ARTIQ-Python import machinery -urukul_sta_pll_lock = urukul.urukul_sta_pll_lock -urukul_sta_smp_err = urukul.urukul_sta_smp_err __all__ = [ "AD9910", @@ -62,8 +82,12 @@ RAM_MODE_CONT_RAMPUP = 4 # Default profile for RAM mode _DEFAULT_PROFILE_RAM = 0 - +@nac3 class SyncDataUser: + core: KernelInvariant[Core] + sync_delay_seed: Kernel[int32] + io_update_delay: Kernel[int32] + def __init__(self, core, sync_delay_seed, io_update_delay): self.core = core self.sync_delay_seed = sync_delay_seed @@ -74,7 +98,14 @@ class SyncDataUser: pass +@nac3 class SyncDataEeprom: + core: KernelInvariant[Core] + eeprom_device: KernelInvariant[KasliEEPROM] # NAC3TODO support generic EEPROM driver + eeprom_offset: KernelInvariant[int32] + sync_delay_seed: Kernel[int32] + io_update_delay: Kernel[int32] + def __init__(self, dmgr, core, eeprom_str): self.core = core @@ -100,6 +131,7 @@ class SyncDataEeprom: self.io_update_delay = int32(io_update_delay) +@nac3 class AD9910: """ AD9910 DDS channel on Urukul. @@ -136,9 +168,24 @@ class AD9910: to the same string value. """ + core: KernelInvariant[Core] + cpld: KernelInvariant[CPLD] + bus: KernelInvariant[SPIMaster] + chip_select: KernelInvariant[int32] + pll_en: KernelInvariant[bool] + pll_n: KernelInvariant[int32] + pll_vco: KernelInvariant[int32] + pll_cp: KernelInvariant[int32] + ftw_per_hz: KernelInvariant[float] + sysclk_per_mu: KernelInvariant[int32] + sysclk: KernelInvariant[float] + sw: KernelInvariant[TTLOut] + sync_data: KernelInvariant[SyncDataUser] + phase_mode: Kernel[int32] + def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=-1, - io_update_delay=0, pll_en=1): + io_update_delay=0, pll_en=True): self.kernel_invariants = {"cpld", "core", "bus", "chip_select", "pll_en", "pll_n", "pll_vco", "pll_cp", "ftw_per_hz", "sysclk_per_mu", "sysclk", @@ -150,7 +197,7 @@ class AD9910: self.chip_select = chip_select if sw_device: self.sw = dmgr.get(sw_device) - self.kernel_invariants.add("sw") + # NAC3TODO: support no sw clk = self.cpld.refclk / [4, 1, 2, 4][self.cpld.clk_div] self.pll_en = pll_en self.pll_n = pll_n @@ -172,6 +219,7 @@ class AD9910: self.sysclk_per_mu = int(round(sysclk * self.core.ref_period)) self.sysclk = sysclk + # NAC3TODO if isinstance(sync_delay_seed, str) or isinstance(io_update_delay, str): if sync_delay_seed != io_update_delay: @@ -236,8 +284,8 @@ class AD9910: :param addr: Register address :param data: Data to be written """ - self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 24, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG | SPI_END, 24, + SPIT_DDS_WR, self.chip_select) self.bus.write((addr << 24) | ((data & 0xffff) << 8)) @kernel @@ -247,11 +295,11 @@ class AD9910: :param addr: Register address :param data: Data to be written """ - self.bus.set_config_mu(urukul.SPI_CONFIG, 8, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG, 8, + SPIT_DDS_WR, self.chip_select) self.bus.write(addr << 24) - self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG | SPI_END, 32, + SPIT_DDS_WR, self.chip_select) self.bus.write(data) @kernel @@ -260,12 +308,12 @@ class AD9910: :param addr: Register address """ - self.bus.set_config_mu(urukul.SPI_CONFIG, 8, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG, 8, + SPIT_DDS_WR, self.chip_select) self.bus.write((addr | 0x80) << 24) self.bus.set_config_mu( - urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, - 16, urukul.SPIT_DDS_RD, self.chip_select) + SPI_CONFIG | SPI_END | SPI_INPUT, + 16, SPIT_DDS_RD, self.chip_select) self.bus.write(0) return self.bus.read() @@ -275,12 +323,12 @@ class AD9910: :param addr: Register address """ - self.bus.set_config_mu(urukul.SPI_CONFIG, 8, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG, 8, + SPIT_DDS_WR, self.chip_select) self.bus.write((addr | 0x80) << 24) self.bus.set_config_mu( - urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, - 32, urukul.SPIT_DDS_RD, self.chip_select) + SPI_CONFIG | SPI_END | SPI_INPUT, + 32, SPIT_DDS_RD, self.chip_select) self.bus.write(0) return self.bus.read() @@ -292,20 +340,20 @@ class AD9910: :return: 64 bit integer register value """ self.bus.set_config_mu( - urukul.SPI_CONFIG, 8, - urukul.SPIT_DDS_WR, self.chip_select) + SPI_CONFIG, 8, + SPIT_DDS_WR, self.chip_select) self.bus.write((addr | 0x80) << 24) self.bus.set_config_mu( - urukul.SPI_CONFIG | spi.SPI_INPUT, 32, - urukul.SPIT_DDS_RD, self.chip_select) + SPI_CONFIG | SPI_INPUT, 32, + SPIT_DDS_RD, self.chip_select) self.bus.write(0) self.bus.set_config_mu( - urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 32, - urukul.SPIT_DDS_RD, self.chip_select) + SPI_CONFIG | SPI_END | SPI_INPUT, 32, + SPIT_DDS_RD, self.chip_select) self.bus.write(0) hi = self.bus.read() lo = self.bus.read() - return (int64(hi) << 32) | lo + return (int64(hi) << int64(32)) | int64(lo) @kernel def write64(self, addr: int32, data_high: int32, data_low: int32): @@ -315,14 +363,14 @@ class AD9910: :param data_high: High (MSB) 32 bits of the data :param data_low: Low (LSB) 32 data bits """ - self.bus.set_config_mu(urukul.SPI_CONFIG, 8, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG, 8, + SPIT_DDS_WR, self.chip_select) self.bus.write(addr << 24) - self.bus.set_config_mu(urukul.SPI_CONFIG, 32, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG, 32, + SPIT_DDS_WR, self.chip_select) self.bus.write(data_high) - self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG | SPI_END, 32, + SPIT_DDS_WR, self.chip_select) self.bus.write(data_low) @kernel @@ -335,15 +383,15 @@ class AD9910: :param data: Data to be written to RAM. """ - self.bus.set_config_mu(urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, + self.bus.set_config_mu(SPI_CONFIG, 8, SPIT_DDS_WR, self.chip_select) self.bus.write(_AD9910_REG_RAM << 24) - self.bus.set_config_mu(urukul.SPI_CONFIG, 32, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG, 32, + SPIT_DDS_WR, self.chip_select) for i in range(len(data) - 1): self.bus.write(data[i]) - self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32, - urukul.SPIT_DDS_WR, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG | SPI_END, 32, + SPIT_DDS_WR, self.chip_select) self.bus.write(data[len(data) - 1]) @kernel @@ -356,21 +404,21 @@ class AD9910: :param data: List to be filled with data read from RAM. """ - self.bus.set_config_mu(urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, + self.bus.set_config_mu(SPI_CONFIG, 8, SPIT_DDS_WR, self.chip_select) self.bus.write((_AD9910_REG_RAM | 0x80) << 24) n = len(data) - 1 if n > 0: - self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_INPUT, 32, - urukul.SPIT_DDS_RD, self.chip_select) + self.bus.set_config_mu(SPI_CONFIG | SPI_INPUT, 32, + SPIT_DDS_RD, self.chip_select) preload = min(n, 8) for i in range(n): self.bus.write(0) if i >= preload: data[i - preload] = self.bus.read() self.bus.set_config_mu( - urukul.SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 32, - urukul.SPIT_DDS_RD, self.chip_select) + SPI_CONFIG | SPI_INPUT | SPI_END, 32, + SPIT_DDS_RD, self.chip_select) self.bus.write(0) for i in range(preload + 1): data[(n - preload) + i] = self.bus.read() @@ -463,50 +511,50 @@ class AD9910: if self.sync_data.sync_delay_seed >= 0 and not self.cpld.sync_div: raise ValueError("parent cpld does not drive SYNC") if self.sync_data.sync_delay_seed >= 0: - if self.sysclk_per_mu != self.sysclk * self.core.ref_period: + if float(self.sysclk_per_mu) != self.sysclk * self.core.ref_period: raise ValueError("incorrect clock ratio for synchronization") - delay(50 * ms) # slack + self.core.delay(50. * ms) # slack # Set SPI mode self.set_cfr1() - self.cpld.io_update.pulse(1 * us) - delay(1 * ms) + self.cpld.io_update.pulse(1. * us) + self.core.delay(1. * ms) if not blind: # Use the AUX DAC setting to identify and confirm presence aux_dac = self.read32(_AD9910_REG_AUX_DAC) if aux_dac & 0xff != 0x7f: raise ValueError("Urukul AD9910 AUX_DAC mismatch") - delay(50 * us) # slack + self.core.delay(50. * us) # slack # Configure PLL settings and bring up PLL # enable amplitude scale from profiles # read effective FTW # sync timing validation disable (enabled later) self.set_cfr2(sync_validation_disable=1) - self.cpld.io_update.pulse(1 * us) + self.cpld.io_update.pulse(1. * us) cfr3 = (0x0807c000 | (self.pll_vco << 24) | - (self.pll_cp << 19) | (self.pll_en << 8) | - (self.pll_n << 1)) + (self.pll_cp << 19) | (int32(self.pll_en) << 8) | + (int32(self.pll_n) << 1)) self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset - self.cpld.io_update.pulse(1 * us) + self.cpld.io_update.pulse(1. * us) if self.pll_en: self.write32(_AD9910_REG_CFR3, cfr3) - self.cpld.io_update.pulse(1 * us) + self.cpld.io_update.pulse(1. * us) if blind: - delay(100 * ms) + self.core.delay(100. * ms) else: # Wait for PLL lock, up to 100 ms for i in range(100): sta = self.cpld.sta_read() lock = urukul_sta_pll_lock(sta) - delay(1 * ms) - if lock & (1 << self.chip_select - 4): + self.core.delay(1. * ms) + if lock & (1 << self.chip_select - 4) != 0: break if i >= 100 - 1: raise ValueError("PLL lock timeout") - delay(10 * us) # slack + self.core.delay(10. * us) # slack if self.sync_data.sync_delay_seed >= 0 and not blind: self.tune_sync_delay(self.sync_data.sync_delay_seed) - delay(1 * ms) + self.core.delay(1. * ms) @kernel def power_down(self, bits: int32 = 0b1111): @@ -515,7 +563,7 @@ class AD9910: :param bits: Power down bits, see datasheet """ self.set_cfr1(power_down=bits) - self.cpld.io_update.pulse(1 * us) + self.cpld.io_update.pulse(1. * us) @kernel def set_mu(self, ftw: int32 = 0, pow_: int32 = 0, asf: int32 = 0x3fff, @@ -557,15 +605,15 @@ class AD9910: phase_mode = self.phase_mode # Align to coarse RTIO which aligns SYNC_CLK. I.e. clear fine TSC # This will not cause a collision or sequence error. - at_mu(now_mu() & ~7) + at_mu(now_mu() & int64(~7)) if phase_mode != PHASE_MODE_CONTINUOUS: # Auto-clear phase accumulator on IO_UPDATE. # This is active already for the next IO_UPDATE self.set_cfr1(phase_autoclear=1) - if phase_mode == PHASE_MODE_TRACKING and ref_time_mu < 0: + if phase_mode == PHASE_MODE_TRACKING and ref_time_mu < int64(0): # set default fiducial time stamp - ref_time_mu = 0 - if ref_time_mu >= 0: + ref_time_mu = int64(0) + if ref_time_mu >= int64(0): # 32 LSB are sufficient. # Also no need to use IO_UPDATE time as this # is equivalent to an output pipeline latency. @@ -583,8 +631,8 @@ class AD9910: if not ram_destination == RAM_DEST_POW: self.set_pow(pow_) delay_mu(int64(self.sync_data.io_update_delay)) - self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYN_CCLK - at_mu(now_mu() & ~7) # clear fine TSC again + self.cpld.io_update.pulse_mu(int64(8)) # assumes 8 mu > t_SYN_CCLK + at_mu(now_mu() & int64(~7)) # clear fine TSC again if phase_mode != PHASE_MODE_CONTINUOUS: self.set_cfr1() # future IO_UPDATE will activate @@ -606,8 +654,8 @@ class AD9910: data = int64(self.read64(_AD9910_REG_PROFILE0 + profile)) # Extract and return fields ftw = int32(data) - pow_ = int32((data >> 32) & 0xffff) - asf = int32((data >> 48) & 0x3fff) + pow_ = int32(data >> int64(32)) & 0xffff + asf = int32(data >> int64(48)) & 0x3fff return ftw, pow_, asf @kernel @@ -703,13 +751,13 @@ class AD9910: """Return the frequency corresponding to the given frequency tuning word. """ - return ftw / self.ftw_per_hz + return float(ftw) / self.ftw_per_hz @portable def turns_to_pow(self, turns: float) -> int32: """Return the 16-bit phase offset word corresponding to the given phase in turns.""" - return int32(round(turns * 0x10000)) & int32(0xffff) + return round(turns * float(0x10000)) & 0xffff @portable def pow_to_turns(self, pow_: int32) -> float: @@ -721,7 +769,7 @@ class AD9910: def amplitude_to_asf(self, amplitude: float) -> int32: """Return 14-bit amplitude scale factor corresponding to given fractional amplitude.""" - code = int32(round(amplitude * 0x3fff)) + code = round(amplitude * float(0x3fff)) if code < 0 or code > 0x3fff: raise ValueError("Invalid AD9910 fractional amplitude!") return code @@ -730,7 +778,7 @@ class AD9910: def asf_to_amplitude(self, asf: int32) -> float: """Return amplitude as a fraction of full scale corresponding to given amplitude scale factor.""" - return asf / float(0x3fff) + return float(asf) / float(0x3fff) @portable def frequency_to_ram(self, frequency: list[float], ram: list[int32]): @@ -972,10 +1020,10 @@ class AD9910: Also modifies CFR2. """ self.set_cfr2(sync_validation_disable=1) # clear SMP_ERR - self.cpld.io_update.pulse(1 * us) - delay(10 * us) # slack + self.cpld.io_update.pulse(1. * us) + self.core.delay(10. * us) # slack self.set_cfr2(sync_validation_disable=0) # enable SMP_ERR - self.cpld.io_update.pulse(1 * us) + self.cpld.io_update.pulse(1. * us) @kernel def tune_sync_delay(self, @@ -1006,7 +1054,7 @@ class AD9910: next_seed = -1 for in_delay in range(search_span - 2 * window): # alternate search direction around search_seed - if in_delay & 1: + if in_delay & 1 != 0: in_delay = -in_delay in_delay = search_seed + (in_delay >> 1) if in_delay < 0 or in_delay > 31: @@ -1014,9 +1062,9 @@ class AD9910: self.set_sync(in_delay, window) self.clear_smp_err() # integrate SMP_ERR statistics for a few hundred cycles - delay(100 * us) + self.core.delay(100. * us) err = urukul_sta_smp_err(self.cpld.sta_read()) - delay(100 * us) # slack + self.core.delay(100. * us) # slack if not (err >> (self.chip_select - 4)) & 1: next_seed = in_delay break @@ -1028,7 +1076,7 @@ class AD9910: window = max(min_window, window - 1 - margin) self.set_sync(search_seed, window) self.clear_smp_err() - delay(100 * us) # slack + self.core.delay(100. * us) # slack return search_seed, window else: break @@ -1060,21 +1108,21 @@ class AD9910: # dFTW = 1, (work around negative slope) self.write64(_AD9910_REG_RAMP_STEP, -1, 0) # delay io_update after RTIO edge - t = now_mu() + 8 & ~7 + t = now_mu() + int64(8) & int64(~7) at_mu(t + delay_start) # assumes a maximum t_SYNC_CLK period - self.cpld.io_update.pulse_mu(16 - delay_start) # realign + self.cpld.io_update.pulse_mu(int64(16) - delay_start) # realign # disable DRG autoclear and LRR on io_update self.set_cfr1() # stop DRG self.write64(_AD9910_REG_RAMP_STEP, 0, 0) - at_mu(t + 0x1000 + delay_stop) - self.cpld.io_update.pulse_mu(16 - delay_stop) # realign + at_mu(t + int64(0x1000) + delay_stop) + self.cpld.io_update.pulse_mu(int64(16) - delay_stop) # realign ftw = self.read32(_AD9910_REG_FTW) # read out effective FTW - delay(100 * us) # slack + self.core.delay(100. * us) # slack # disable DRG self.set_cfr2(drg_enable=0) - self.cpld.io_update.pulse_mu(8) + self.cpld.io_update.pulse_mu(int64(8)) return ftw & 1 @kernel @@ -1100,14 +1148,14 @@ class AD9910: t = 0 # check whether the sync edge is strictly between i, i+2 for j in range(repeat): - t += self.measure_io_update_alignment(i, i + 2) + t += self.measure_io_update_alignment(int64(i), int64(i + 2)) if t != 0: # no certain edge continue # check left/right half: i,i+1 and i+1,i+2 t1 = [0, 0] for j in range(repeat): - t1[0] += self.measure_io_update_alignment(i, i + 1) - t1[1] += self.measure_io_update_alignment(i + 1, i + 2) + t1[0] += self.measure_io_update_alignment(int64(i), int64(i + 1)) + t1[1] += self.measure_io_update_alignment(int64(i + 1), int64(i + 2)) if ((t1[0] == 0 and t1[1] == 0) or (t1[0] == repeat and t1[1] == repeat)): # edge is not close to i + 1, can't interpret result diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json index 45c946d3e..ea70bc98f 100644 --- a/artiq/examples/nac3devices/nac3devices.json +++ b/artiq/examples/nac3devices/nac3devices.json @@ -22,28 +22,34 @@ "ports": [2, 3], "clk_sel": 2 }, + { + "type": "urukul", + "dds": "ad9910", + "ports": [4, 5], + "clk_sel": 2 + }, { "type": "sampler", - "ports": [4] + "ports": [6] }, { "type": "dio", - "ports": [5], + "ports": [7], "bank_direction_low": "input", "bank_direction_high": "output", "edge_counter": true }, { "type": "grabber", - "ports": [6] + "ports": [8] }, { "type": "fastino", - "ports": [7] + "ports": [9] }, { "type": "phaser", - "ports": [8] + "ports": [10] } ] } diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index 4cf5180b1..caf65abae 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -7,6 +7,7 @@ from artiq.coredevice.mirny import Mirny as MirnyCPLD from artiq.coredevice.adf5356 import ADF5356 from artiq.coredevice.urukul import CPLD as UrukulCPLD from artiq.coredevice.ad9912 import AD9912 +from artiq.coredevice.ad9910 import AD9910 from artiq.coredevice.sampler import Sampler from artiq.coredevice.edge_counter import EdgeCounter from artiq.coredevice.grabber import Grabber @@ -24,6 +25,8 @@ class NAC3Devices(EnvExperiment): urukul0_cpld: KernelInvariant[UrukulCPLD] eeprom_urukul0: KernelInvariant[KasliEEPROM] urukul0_ch0: KernelInvariant[AD9912] + urukul1_cpld: KernelInvariant[UrukulCPLD] + urukul1_ch0: KernelInvariant[AD9910] sampler0: KernelInvariant[Sampler] ttl0_counter: KernelInvariant[EdgeCounter] grabber0: KernelInvariant[Grabber] @@ -39,6 +42,8 @@ class NAC3Devices(EnvExperiment): self.setattr_device("urukul0_cpld") self.setattr_device("eeprom_urukul0") self.setattr_device("urukul0_ch0") + self.setattr_device("urukul1_cpld") + self.setattr_device("urukul1_ch0") self.setattr_device("sampler0") self.setattr_device("ttl0_counter") self.setattr_device("grabber0") From 8fc0e5d3aa53743e9c6b379cf3887b38f360e8d3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 Mar 2022 08:55:27 +0800 Subject: [PATCH 117/352] suservo: port to NAC3 --- artiq/coredevice/suservo.py | 117 ++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 46 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 1d0a72dad..3f18fc604 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -1,8 +1,19 @@ -from artiq.language.core import kernel, delay, delay_mu, portable +from numpy import int32, int64 + +from artiq.language.core import * from artiq.language.units import us, ns +from artiq.coredevice.core import Core from artiq.coredevice.rtio import rtio_output, rtio_input_data -from artiq.coredevice import spi2 as spi -from artiq.coredevice import urukul, sampler +from artiq.coredevice.spi2 import SPI_END, SPIMaster +from artiq.coredevice.urukul import CFG_MASK_NU, CPLD +from artiq.coredevice.ad9910 import AD9910 +from artiq.coredevice.sampler import adc_mu_to_volt as sampler_adc_mu_to_volt, SPI_CONFIG as SAMPLER_SPI_CONFIG, SPI_CS_PGIA as SAMPLER_SPI_CS_PGIA + + +# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 +@nac3 +class ValueError(Exception): + pass COEFF_WIDTH = 18 @@ -17,20 +28,21 @@ COEFF_SHIFT = 11 @portable -def y_mu_to_full_scale(y): +def y_mu_to_full_scale(y: int32) -> float: """Convert servo Y data from machine units to units of full scale.""" - return y / Y_FULL_SCALE_MU + return float(y) / float(Y_FULL_SCALE_MU) @portable -def adc_mu_to_volts(x, gain): +def adc_mu_to_volts(x: int32, gain: int32) -> float: """Convert servo ADC data from machine units to Volt.""" val = (x >> 1) & 0xffff mask = 1 << 15 val = -(val & mask) + (val & ~mask) - return sampler.adc_mu_to_volt(val, gain) + return sampler_adc_mu_to_volt(val, gain) +@nac3 class SUServo: """Sampler-Urukul Servo parent and configuration device. @@ -64,8 +76,15 @@ class SUServo: between experiments. :param core_device: Core device name """ - kernel_invariants = {"channel", "core", "pgia", "cplds", "ddses", - "ref_period_mu"} + + core: KernelInvariant[Core] + pgia: KernelInvariant[SPIMaster] + ddses: KernelInvariant[list[AD9910]] + cplds: KernelInvariant[list[CPLD]] + channel: KernelInvariant[int32] + gains: Kernel[int32] + ref_period_mu: KernelInvariant[int64] + def __init__(self, dmgr, channel, pgia_device, cpld_devices, dds_devices, @@ -97,11 +116,11 @@ class SUServo: or the channel controls. """ self.set_config(enable=0) - delay(3*us) # pipeline flush + self.core.delay(3.*us) # pipeline flush self.pgia.set_config_mu( - sampler.SPI_CONFIG | spi.SPI_END, - 16, 4, sampler.SPI_CS_PGIA) + SAMPLER_SPI_CONFIG | SPI_END, + 16, 4, SAMPLER_SPI_CS_PGIA) for i in range(len(self.cplds)): cpld = self.cplds[i] @@ -109,12 +128,12 @@ class SUServo: cpld.init(blind=True) prev_cpld_cfg = cpld.cfg_reg - cpld.cfg_write(prev_cpld_cfg | (0xf << urukul.CFG_MASK_NU)) + cpld.cfg_write(prev_cpld_cfg | (0xf << CFG_MASK_NU)) dds.init(blind=True) cpld.cfg_write(prev_cpld_cfg) @kernel - def write(self, addr, value): + def write(self, addr: int32, value: int32): """Write to servo memory. This method advances the timeline by one coarse RTIO cycle. @@ -130,7 +149,7 @@ class SUServo: delay_mu(self.ref_period_mu) @kernel - def read(self, addr): + def read(self, addr: int32) -> int32: """Read from servo memory. This method does not advance the timeline but consumes all slack. @@ -143,7 +162,7 @@ class SUServo: return rtio_input_data(self.channel) @kernel - def set_config(self, enable): + def set_config(self, enable: int32): """Set SU Servo configuration. This method advances the timeline by one servo memory access. @@ -161,7 +180,7 @@ class SUServo: self.write(CONFIG_ADDR, enable) @kernel - def get_status(self): + def get_status(self) -> int32: """Get current SU Servo status. This method does not advance the timeline but consumes all slack. @@ -182,7 +201,7 @@ class SUServo: return self.read(CONFIG_ADDR) @kernel - def get_adc_mu(self, adc): + def get_adc_mu(self, adc: int32) -> int32: """Get the latest ADC reading (IIR filter input X0) in machine units. This method does not advance the timeline but consumes all slack. @@ -200,7 +219,7 @@ class SUServo: return self.read(STATE_SEL | (adc << 1) | (1 << 8)) @kernel - def set_pgia_mu(self, channel, gain): + def set_pgia_mu(self, channel: int32, gain: int32): """Set instrumentation amplifier gain of a ADC channel. The four gain settings (0, 1, 2, 3) corresponds to gains of @@ -216,7 +235,7 @@ class SUServo: self.gains = gains @kernel - def get_adc(self, channel): + def get_adc(self, channel: int32) -> float: """Get the latest ADC reading (IIR filter input X0). This method does not advance the timeline but consumes all slack. @@ -237,13 +256,19 @@ class SUServo: return adc_mu_to_volts(val, gain) +@nac3 class Channel: """Sampler-Urukul Servo channel :param channel: RTIO channel number :param servo_device: Name of the parent SUServo device """ - kernel_invariants = {"channel", "core", "servo", "servo_channel"} + + core: KernelInvariant[Core] + servo: KernelInvariant[SUServo] + channel: KernelInvariant[int32] + servo_channel: KernelInvariant[int32] + dds: KernelInvariant[AD9910] def __init__(self, dmgr, channel, servo_device): self.servo = dmgr.get(servo_device) @@ -256,7 +281,7 @@ class Channel: self.dds = self.servo.ddses[self.servo_channel // 4] @kernel - def set(self, en_out, en_iir=0, profile=0): + def set(self, en_out: bool, en_iir: bool = False, profile: int32 = 0): """Operate channel. This method does not advance the timeline. Output RF switch setting @@ -272,10 +297,10 @@ class Channel: :param profile: Active profile (0-31) """ rtio_output(self.channel << 8, - en_out | (en_iir << 1) | (profile << 2)) + int32(en_out) | (int32(en_iir) << 1) | (profile << 2)) @kernel - def set_dds_mu(self, profile, ftw, offs, pow_=0): + def set_dds_mu(self, profile: int32, ftw: int32, offs: int32, pow_: int32 = 0): """Set profile DDS coefficients in machine units. .. seealso:: :meth:`set_amplitude` @@ -292,7 +317,7 @@ class Channel: self.servo.write(base + 2, pow_) @kernel - def set_dds(self, profile, frequency, offset, phase=0.): + def set_dds(self, profile: int32, frequency: float, offset: float, phase: float = 0.): """Set profile DDS coefficients. This method advances the timeline by four servo memory accesses. @@ -311,7 +336,7 @@ class Channel: self.set_dds_mu(profile, ftw, offs, pow_) @kernel - def set_dds_offset_mu(self, profile, offs): + def set_dds_offset_mu(self, profile: int32, offs: int32): """Set only IIR offset in DDS coefficient profile. See :meth:`set_dds_mu` for setting the complete DDS profile. @@ -323,7 +348,7 @@ class Channel: self.servo.write(base + 4, offs) @kernel - def set_dds_offset(self, profile, offset): + def set_dds_offset(self, profile: int32, offset: float): """Set only IIR offset in DDS coefficient profile. See :meth:`set_dds` for setting the complete DDS profile. @@ -334,7 +359,7 @@ class Channel: self.set_dds_offset_mu(profile, self.dds_offset_to_mu(offset)) @portable - def dds_offset_to_mu(self, offset): + def dds_offset_to_mu(self, offset: float) -> int32: """Convert IIR offset (negative setpoint) from units of full scale to machine units (see :meth:`set_dds_mu`, :meth:`set_dds_offset_mu`). @@ -342,10 +367,10 @@ class Channel: rounding and representation as two's complement, ``offset=1`` can not be represented while ``offset=-1`` can. """ - return int(round(offset * (1 << COEFF_WIDTH - 1))) + return round(offset * float(1 << COEFF_WIDTH - 1)) @kernel - def set_iir_mu(self, profile, adc, a1, b0, b1, dly=0): + def set_iir_mu(self, profile: int32, adc: int32, a1: int32, b0: int32, b1: int32, dly: int32 = 0): """Set profile IIR coefficients in machine units. The recurrence relation is (all data signed and MSB aligned): @@ -385,7 +410,7 @@ class Channel: self.servo.write(base + 7, b0) @kernel - def set_iir(self, profile, adc, kp, ki=0., g=0., delay=0.): + def set_iir(self, profile: int32, adc: int32, kp: float, ki: float = 0., g: float = 0., delay: float = 0.): """Set profile IIR coefficients. This method advances the timeline by four servo memory accesses. @@ -427,23 +452,23 @@ class Channel: A_NORM = 1 << COEFF_SHIFT COEFF_MAX = 1 << COEFF_WIDTH - 1 - kp *= B_NORM + kp *= float(B_NORM) if ki == 0.: # pure P a1 = 0 b1 = 0 - b0 = int(round(kp)) + b0 = round(kp) else: # I or PI - ki *= B_NORM*T_CYCLE/2. + ki *= float(B_NORM)*T_CYCLE/2. if g == 0.: c = 1. a1 = A_NORM else: - c = 1./(1. + ki/(g*B_NORM)) - a1 = int(round((2.*c - 1.)*A_NORM)) - b0 = int(round(kp + ki*c)) - b1 = int(round(kp + (ki - 2.*kp)*c)) + c = 1./(1. + ki/(g*float(B_NORM))) + a1 = round((2.*c - 1.)*float(A_NORM)) + b0 = round(kp + ki*c) + b1 = round(kp + (ki - 2.*kp)*c) if b1 == -b0: raise ValueError("low integrator gain and/or gain limit") @@ -451,11 +476,11 @@ class Channel: b1 >= COEFF_MAX or b1 < -COEFF_MAX): raise ValueError("high gains") - dly = int(round(delay/T_CYCLE)) + dly = round(delay/T_CYCLE) self.set_iir_mu(profile, adc, a1, b0, b1, dly) @kernel - def get_profile_mu(self, profile, data): + def get_profile_mu(self, profile: int32, data: list[int32]): """Retrieve profile data. Profile data is returned in the ``data`` argument in machine units @@ -473,10 +498,10 @@ class Channel: base = (self.servo_channel << 8) | (profile << 3) for i in range(len(data)): data[i] = self.servo.read(base + i) - delay(4*us) + self.core.delay(4.*us) @kernel - def get_y_mu(self, profile): + def get_y_mu(self, profile: int32) -> int32: """Get a profile's IIR state (filter output, Y0) in machine units. The IIR state is also know as the "integrator", or the DDS amplitude @@ -494,7 +519,7 @@ class Channel: return self.servo.read(STATE_SEL | (self.servo_channel << 5) | profile) @kernel - def get_y(self, profile): + def get_y(self, profile: int32) -> float: """Get a profile's IIR state (filter output, Y0). The IIR state is also know as the "integrator", or the DDS amplitude @@ -512,7 +537,7 @@ class Channel: return y_mu_to_full_scale(self.get_y_mu(profile)) @kernel - def set_y_mu(self, profile, y): + def set_y_mu(self, profile: int32, y: int32): """Set a profile's IIR state (filter output, Y0) in machine units. The IIR state is also know as the "integrator", or the DDS amplitude @@ -532,7 +557,7 @@ class Channel: self.servo.write(STATE_SEL | (self.servo_channel << 5) | profile, y) @kernel - def set_y(self, profile, y): + def set_y(self, profile: int32, y: float) -> int32: """Set a profile's IIR state (filter output, Y0). The IIR state is also know as the "integrator", or the DDS amplitude @@ -547,7 +572,7 @@ class Channel: :param profile: Profile number (0-31) :param y: IIR state in units of full scale """ - y_mu = int(round(y * Y_FULL_SCALE_MU)) + y_mu = round(y * float(Y_FULL_SCALE_MU)) if y_mu < 0 or y_mu > (1 << 17) - 1: raise ValueError("Invalid SUServo y-value!") self.set_y_mu(profile, y_mu) From b7d35446e2f69b3f2f87c2f8e7849dc6ae7750d5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 3 Mar 2022 16:24:07 +0800 Subject: [PATCH 118/352] almazny: port to NAC3 --- artiq/coredevice/mirny.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py index 55d03f855..9ac7644ee 100644 --- a/artiq/coredevice/mirny.py +++ b/artiq/coredevice/mirny.py @@ -191,6 +191,7 @@ class Mirny: self.bus.write(data) +@nac3 class Almazny: """ Almazny (High frequency mezzanine board for Mirny) @@ -198,6 +199,12 @@ class Almazny: :param host_mirny - Mirny device Almazny is connected to """ + core: KernelInvariant[Core] + mirny_cpld: KernelInvariant[Mirny] + att_mu: Kernel[list[int32]] + channel_sw: Kernel[list[int32]] + output_enable: Kernel[bool] + def __init__(self, dmgr, host_mirny): self.mirny_cpld = dmgr.get(host_mirny) self.att_mu = [0x3f] * 4 @@ -209,7 +216,7 @@ class Almazny: self.output_toggle(self.output_enable) @kernel - def att_to_mu(self, att): + def att_to_mu(self, att: float) -> int32: """ Convert an attenuator setting in dB to machine units. @@ -222,17 +229,17 @@ class Almazny: return mu @kernel - def mu_to_att(self, att_mu): + def mu_to_att(self, att_mu: int32) -> float: """ Convert a digital attenuator setting to dB. :param att_mu: attenuator setting in machine units :return: attenuator setting in dB """ - return att_mu / 2 + return float(att_mu) / 2. @kernel - def set_att(self, channel, att, rf_switch=True): + def set_att(self, channel: int32, att: float, rf_switch: bool = True): """ Sets attenuators on chosen shift register (channel). :param channel - index of the register [0-3] @@ -242,7 +249,7 @@ class Almazny: self.set_att_mu(channel, self.att_to_mu(att), rf_switch) @kernel - def set_att_mu(self, channel, att_mu, rf_switch=True): + def set_att_mu(self, channel: int32, att_mu: int32, rf_switch: bool = True): """ Sets attenuators on chosen shift register (channel). :param channel - index of the register [0-3] @@ -254,7 +261,7 @@ class Almazny: self._update_register(channel) @kernel - def output_toggle(self, oe): + def output_toggle(self, oe: bool): """ Toggles output on all shift registers on or off. :param oe - toggle output enable (bool) @@ -262,13 +269,13 @@ class Almazny: self.output_enable = oe cfg_reg = self.mirny_cpld.read_reg(1) en = 1 if self.output_enable else 0 - delay(100 * us) + self.core.delay(100. * us) new_reg = (en << ALMAZNY_OE_SHIFT) | (cfg_reg & 0x3FF) self.mirny_cpld.write_reg(1, new_reg) - delay(100 * us) + self.core.delay(100. * us) @kernel - def _flip_mu_bits(self, mu): + def _flip_mu_bits(self, mu: int32) -> int32: # in this form MSB is actually 0.5dB attenuator # unnatural for users, so we flip the six bits return (((mu & 0x01) << 5) @@ -279,16 +286,16 @@ class Almazny: | ((mu & 0x20) >> 5)) @kernel - def _update_register(self, ch): + def _update_register(self, ch: int32): self.mirny_cpld.write_ext( ALMAZNY_REG_BASE + ch, 8, self._flip_mu_bits(self.att_mu[ch]) | (self.channel_sw[ch] << 6), ALMAZNY_SPIT_WR ) - delay(100 * us) + self.core.delay(100. * us) @kernel def _update_all_registers(self): for i in range(4): - self._update_register(i) \ No newline at end of file + self._update_register(i) From ba106de24f790e6db5793c70a3003d5370760cc2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 3 Mar 2022 17:07:05 +0800 Subject: [PATCH 119/352] suservo: use bool for enable --- artiq/coredevice/suservo.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 3f18fc604..7ea8eef11 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -115,7 +115,7 @@ class SUServo: This method does not alter the profile configuration memory or the channel controls. """ - self.set_config(enable=0) + self.set_config(enable=False) self.core.delay(3.*us) # pipeline flush self.pgia.set_config_mu( @@ -162,7 +162,7 @@ class SUServo: return rtio_input_data(self.channel) @kernel - def set_config(self, enable: int32): + def set_config(self, enable: bool): """Set SU Servo configuration. This method advances the timeline by one servo memory access. @@ -177,7 +177,7 @@ class SUServo: Disabling takes up to two servo cycles (~2.3 µs) to clear the processing pipeline. """ - self.write(CONFIG_ADDR, enable) + self.write(CONFIG_ADDR, int32(enable)) @kernel def get_status(self) -> int32: From 9d82f968f90fd3ebdb2af96b1e18447114cd1260 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 3 Mar 2022 17:07:27 +0800 Subject: [PATCH 120/352] artiq_sinara_tester: port to NAC3 --- artiq/frontend/artiq_sinara_tester.py | 193 ++++++++++++++------------ 1 file changed, 106 insertions(+), 87 deletions(-) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index a4f999029..81e7370f9 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -6,8 +6,21 @@ import os import select import sys +from numpy import int32 + from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut, TTLInOut +from artiq.coredevice.urukul import CPLD as UrukulCPLD from artiq.coredevice.ad9910 import AD9910, SyncDataEeprom +from artiq.coredevice.mirny import Mirny, Almazny +from artiq.coredevice.adf5356 import ADF5356 +from artiq.coredevice.sampler import Sampler +from artiq.coredevice.zotino import Zotino +from artiq.coredevice.fastino import Fastino +from artiq.coredevice.phaser import Phaser +from artiq.coredevice.grabber import Grabber +from artiq.coredevice.suservo import SUServo, Channel as SUServoChannel from artiq.master.databases import DeviceDB from artiq.master.worker_db import DeviceManager @@ -27,7 +40,8 @@ def chunker(seq, size): yield res -def is_enter_pressed() -> TBool: +@rpc +def is_enter_pressed() -> bool: if os.name == "nt": if msvcrt.kbhit() and msvcrt.getch() == b"\r": return True @@ -41,7 +55,10 @@ def is_enter_pressed() -> TBool: return False +@nac3 class SinaraTester(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") @@ -149,7 +166,7 @@ class SinaraTester(EnvExperiment): self.suschannels = sorted(self.suschannels.items(), key=lambda x: x[1].channel) @kernel - def test_led(self, led): + def test_led(self, led: TTLOut): while not is_enter_pressed(): self.core.break_realtime() # do not fill the FIFOs too much to avoid long response times @@ -157,8 +174,8 @@ class SinaraTester(EnvExperiment): while self.core.get_rtio_counter_mu() < t: pass for i in range(3): - led.pulse(100*ms) - delay(100*ms) + led.pulse(100.*ms) + self.core.delay(100.*ms) def test_leds(self): print("*** Testing LEDs.") @@ -169,7 +186,7 @@ class SinaraTester(EnvExperiment): self.test_led(led_dev) @kernel - def test_ttl_out_chunk(self, ttl_chunk): + def test_ttl_out_chunk(self, ttl_chunk: list[TTLOut]): while not is_enter_pressed(): self.core.break_realtime() for _ in range(50000): @@ -177,9 +194,9 @@ class SinaraTester(EnvExperiment): for ttl in ttl_chunk: i += 1 for _ in range(i): - ttl.pulse(1*us) - delay(1*us) - delay(10*us) + ttl.pulse(1.*us) + self.core.delay(1.*us) + self.core.delay(10.*us) def test_ttl_outs(self): print("*** Testing TTL outputs.") @@ -193,16 +210,16 @@ class SinaraTester(EnvExperiment): self.test_ttl_out_chunk([dev for name, dev in ttl_chunk]) @kernel - def test_ttl_in(self, ttl_out, ttl_in): + def test_ttl_in(self, ttl_out: TTLOut, ttl_in: TTLInOut) -> bool: n = 42 self.core.break_realtime() with parallel: - ttl_in.gate_rising(1*ms) + ttl_in.gate_rising(1.*ms) with sequential: - delay(50*us) + self.core.delay(50.*us) for _ in range(n): - ttl_out.pulse(2*us) - delay(2*us) + ttl_out.pulse(2.*us) + self.core.delay(2.*us) return ttl_in.count(now_mu()) == n def test_ttl_ins(self): @@ -227,23 +244,25 @@ class SinaraTester(EnvExperiment): print("FAILED") @kernel - def init_urukul(self, cpld): + def init_urukul(self, cpld: UrukulCPLD): self.core.break_realtime() cpld.init() @kernel - def test_urukul_att(self, cpld): + def test_urukul_att(self, cpld: UrukulCPLD): self.core.break_realtime() for i in range(32): test_word = 1 << i cpld.set_all_att_mu(test_word) readback_word = cpld.get_att_mu() if readback_word != test_word: - print(readback_word, test_word) - raise ValueError + # NAC3TODO print(readback_word, test_word) + # NAC3TODO raise ValueError + pass + # NAC3TODO: AD9912 support @kernel - def calibrate_urukul(self, channel): + def calibrate_urukul(self, channel: AD9910) -> tuple[int32, int32]: self.core.break_realtime() channel.init() self.core.break_realtime() @@ -253,7 +272,7 @@ class SinaraTester(EnvExperiment): return sync_delay_seed, io_update_delay @kernel - def setup_urukul(self, channel, frequency): + def setup_urukul(self, channel: AD9910, frequency: float): self.core.break_realtime() channel.init() channel.set(frequency*MHz) @@ -261,12 +280,12 @@ class SinaraTester(EnvExperiment): channel.set_att(6.) @kernel - def cfg_sw_off_urukul(self, channel): + def cfg_sw_off_urukul(self, channel: AD9910): self.core.break_realtime() channel.cfg_sw(False) @kernel - def rf_switch_wave(self, channels): + def rf_switch_wave(self, channels: list[TTLOut]): while not is_enter_pressed(): self.core.break_realtime() # do not fill the FIFOs too much to avoid long response times @@ -274,8 +293,8 @@ class SinaraTester(EnvExperiment): while self.core.get_rtio_counter_mu() < t: pass for channel in channels: - channel.pulse(100*ms) - delay(100*ms) + channel.pulse(100.*ms) + self.core.delay(100.*ms) # We assume that RTIO channels for switches are grouped by card. def test_urukuls(self): @@ -322,12 +341,12 @@ class SinaraTester(EnvExperiment): self.rf_switch_wave([swi.sw for swi in sw]) @kernel - def init_mirny(self, cpld): + def init_mirny(self, cpld: Mirny): self.core.break_realtime() cpld.init() @kernel - def setup_mirny(self, channel, frequency): + def setup_mirny(self, channel: ADF5356, frequency: float): self.core.break_realtime() channel.init() @@ -336,15 +355,15 @@ class SinaraTester(EnvExperiment): self.core.break_realtime() channel.set_frequency(frequency*MHz) - delay(5*ms) + self.core.delay(5.*ms) @kernel - def sw_off_mirny(self, channel): + def sw_off_mirny(self, channel: ADF5356): self.core.break_realtime() channel.sw.off() @kernel - def mirny_rf_switch_wave(self, channels): + def mirny_rf_switch_wave(self, channels: list[TTLOut]): while not is_enter_pressed(): self.core.break_realtime() # do not fill the FIFOs too much to avoid long response times @@ -352,26 +371,26 @@ class SinaraTester(EnvExperiment): while self.core.get_rtio_counter_mu() < t: pass for channel in channels: - channel.pulse(100*ms) - delay(100*ms) + channel.pulse(100.*ms) + self.core.delay(100.*ms) @kernel - def init_almazny(self, almazny): + def init_almazny(self, almazny: Almazny): self.core.break_realtime() almazny.init() almazny.output_toggle(True) @kernel - def almazny_set_attenuators_mu(self, almazny, ch, atts): + def almazny_set_attenuators_mu(self, almazny: Almazny, ch: int32, atts: int32): self.core.break_realtime() almazny.set_att_mu(ch, atts) @kernel - def almazny_set_attenuators(self, almazny, ch, atts): + def almazny_set_attenuators(self, almazny: Almazny, ch: int32, atts: float): self.core.break_realtime() almazny.set_att(ch, atts) @kernel - def almazny_toggle_output(self, almazny, rf_on): + def almazny_toggle_output(self, almazny: Almazny, rf_on: bool): self.core.break_realtime() almazny.output_toggle(rf_on) @@ -445,17 +464,21 @@ class SinaraTester(EnvExperiment): self.sw_off_mirny(swi) self.mirny_rf_switch_wave([swi.sw for swi in sw]) + @rpc + def update_sampler_voltages(self, voltages: list[float]): + self.sampler_voltages = voltages + @kernel - def get_sampler_voltages(self, sampler, cb): + def get_sampler_voltages(self, sampler: Sampler): self.core.break_realtime() sampler.init() - delay(5*ms) + self.core.delay(5.*ms) for i in range(8): sampler.set_gain_mu(i, 0) - delay(100*us) - smp = [0.0]*8 + self.core.delay(100.*us) + smp = [0. for _ in range(8)] sampler.sample(smp) - cb(smp) + self.update_sampler_voltages(smp) def test_samplers(self): print("*** Testing Sampler ADCs.") @@ -466,14 +489,10 @@ class SinaraTester(EnvExperiment): print("Apply 1.5V to channel {}. Press ENTER when done.".format(channel)) input() - voltages = [] - def setv(x): - nonlocal voltages - voltages = x - self.get_sampler_voltages(card_dev, setv) + self.get_sampler_voltages(card_dev) passed = True - for n, voltage in enumerate(voltages): + for n, voltage in enumerate(self.sampler_voltages): if n == channel: if abs(voltage - 1.5) > 0.2: passed = False @@ -484,22 +503,22 @@ class SinaraTester(EnvExperiment): print("PASSED") else: print("FAILED") - print(" ".join(["{:.1f}".format(x) for x in voltages])) + print(" ".join(["{:.1f}".format(x) for x in self.sampler_voltages])) @kernel - def set_zotino_voltages(self, zotino, voltages): + def set_zotino_voltages(self, zotino: Zotino, voltages: list[float]): self.core.break_realtime() zotino.init() - delay(200*us) + self.core.delay(200.*us) i = 0 for voltage in voltages: zotino.write_dac(i, voltage) - delay(100*us) + self.core.delay(100.*us) i += 1 zotino.load() @kernel - def zotinos_led_wave(self, zotinos): + def zotinos_led_wave(self, zotinos: list[Zotino]): while not is_enter_pressed(): self.core.break_realtime() # do not fill the FIFOs too much to avoid long response times @@ -509,9 +528,9 @@ class SinaraTester(EnvExperiment): for zotino in zotinos: for i in range(8): zotino.set_leds(1 << i) - delay(100*ms) + self.core.delay(100.*ms) zotino.set_leds(0) - delay(100*ms) + self.core.delay(100.*ms) def test_zotinos(self): print("*** Testing Zotino DACs and USER LEDs.") @@ -527,18 +546,18 @@ class SinaraTester(EnvExperiment): ) @kernel - def set_fastino_voltages(self, fastino, voltages): + def set_fastino_voltages(self, fastino: Fastino, voltages: list[float]): self.core.break_realtime() fastino.init() - delay(200*us) + self.core.delay(200.*us) i = 0 for voltage in voltages: fastino.set_dac(i, voltage) - delay(100*us) + self.core.delay(100.*us) i += 1 @kernel - def fastinos_led_wave(self, fastinos): + def fastinos_led_wave(self, fastinos: list[Fastino]): while not is_enter_pressed(): self.core.break_realtime() # do not fill the FIFOs too much to avoid long response times @@ -548,9 +567,9 @@ class SinaraTester(EnvExperiment): for fastino in fastinos: for i in range(8): fastino.set_leds(1 << i) - delay(100*ms) + self.core.delay(100.*ms) fastino.set_leds(0) - delay(100*ms) + self.core.delay(100.*ms) def test_fastinos(self): print("*** Testing Fastino DACs and USER LEDs.") @@ -566,27 +585,27 @@ class SinaraTester(EnvExperiment): ) @kernel - def set_phaser_frequencies(self, phaser, duc, osc): + def set_phaser_frequencies(self, phaser: Phaser, duc: float, osc: list[float]): self.core.break_realtime() phaser.init() - delay(1*ms) + self.core.delay(1.*ms) phaser.channel[0].set_duc_frequency(duc) phaser.channel[0].set_duc_cfg() - phaser.channel[0].set_att(6*dB) + phaser.channel[0].set_att(6.*dB) phaser.channel[1].set_duc_frequency(-duc) phaser.channel[1].set_duc_cfg() - phaser.channel[1].set_att(6*dB) + phaser.channel[1].set_att(6.*dB) phaser.duc_stb() - delay(1*ms) + self.core.delay(1.*ms) for i in range(len(osc)): phaser.channel[0].oscillator[i].set_frequency(osc[i]) phaser.channel[0].oscillator[i].set_amplitude_phase(.2) phaser.channel[1].oscillator[i].set_frequency(-osc[i]) phaser.channel[1].oscillator[i].set_amplitude_phase(.2) - delay(1*ms) + self.core.delay(1.*ms) @kernel - def phaser_led_wave(self, phasers): + def phaser_led_wave(self, phasers: list[Phaser]): while not is_enter_pressed(): self.core.break_realtime() # do not fill the FIFOs too much to avoid long response times @@ -596,9 +615,9 @@ class SinaraTester(EnvExperiment): for phaser in phasers: for i in range(6): phaser.set_leds(1 << i) - delay(100*ms) + self.core.delay(100.*ms) phaser.set_leds(0) - delay(100*ms) + self.core.delay(100.*ms) def test_phasers(self): print("*** Testing Phaser DACs and 6 USER LEDs.") @@ -617,9 +636,9 @@ class SinaraTester(EnvExperiment): ) @kernel - def grabber_capture(self, card_dev, rois): + def grabber_capture(self, card_dev: Grabber, rois: list[list[int32]]): self.core.break_realtime() - delay(100*us) + self.core.delay(100.*us) mask = 0 for i in range(len(rois)): i = rois[i][0] @@ -630,11 +649,11 @@ class SinaraTester(EnvExperiment): mask |= 1 << i card_dev.setup_roi(i, x0, y0, x1, y1) card_dev.gate_roi(mask) - n = [0]*len(rois) + n = [0 for _ in range(len(rois))] card_dev.input_mu(n) self.core.break_realtime() card_dev.gate_roi(0) - print("ROI sums:", n) + # NAC3TODO print("ROI sums:", n) def test_grabbers(self): print("*** Testing Grabber Frame Grabbers.") @@ -651,25 +670,25 @@ class SinaraTester(EnvExperiment): self.grabber_capture(card_dev, rois) @kernel - def setup_suservo(self, channel): + def setup_suservo(self, channel: SUServo): self.core.break_realtime() channel.init() - delay(1*us) + self.core.delay(1.*us) # ADC PGIA gain 0 for i in range(8): channel.set_pgia_mu(i, 0) - delay(10*us) + self.core.delay(10.*us) # DDS attenuator 10dB for i in range(4): for cpld in channel.cplds: cpld.set_att(i, 10.) - delay(1*us) + self.core.delay(1.*us) # Servo is done and disabled - assert channel.get_status() & 0xff == 2 - delay(10*us) + # NAC3TODO assert channel.get_status() & 0xff == 2 + self.core.delay(10.*us) @kernel - def setup_suservo_loop(self, channel, loop_nr): + def setup_suservo_loop(self, channel: SUServoChannel, loop_nr: int32): self.core.break_realtime() channel.set_y( profile=loop_nr, @@ -684,24 +703,24 @@ class SinaraTester(EnvExperiment): delay=0. # no IIR update delay after enabling ) # setpoint 0.5 (5 V with above PGIA gain setting) - delay(100*us) + self.core.delay(100.*us) channel.set_dds( profile=loop_nr, offset=-.3, # 3 V with above PGIA settings - frequency=10*MHz, + frequency=10.*MHz, phase=0.) # enable RF, IIR updates and set profile - delay(10*us) - channel.set(en_out=1, en_iir=1, profile=loop_nr) + self.core.delay(10.*us) + channel.set(en_out=True, en_iir=True, profile=loop_nr) @kernel - def setup_start_suservo(self, channel): + def setup_start_suservo(self, channel: SUServo): self.core.break_realtime() - channel.set_config(enable=1) - delay(10*us) + channel.set_config(enable=True) + self.core.delay(10.*us) # check servo enabled - assert channel.get_status() & 0x01 == 1 - delay(10*us) + # NAC3TODO assert channel.get_status() & 0x01 == 1 + self.core.delay(10.*us) def test_suservos(self): print("*** Testing SUServos.") From 76132c95c2853dc5b75da4fe9cdf86eb5b7bf607 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 5 Mar 2022 10:28:08 +0800 Subject: [PATCH 121/352] update nac3 --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 1018b5cbe..efcd30abe 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1646061005, - "narHash": "sha256-sofIwwD5lGKzDLClfRITRyeG2mIa0Gvh55XtrWtK8/I=", + "lastModified": 1646423985, + "narHash": "sha256-WXzmupl6WNef65imDgQAvYdU0gRUu3nrbONVgYzQ+/Q=", "ref": "master", - "rev": "d1e172501d8ee745afcf9610516b0993cb9ff410", - "revCount": 617, + "rev": "42fbe8e383bbe454e87dc2c59d8cd3cca67c42f9", + "revCount": 625, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,11 +60,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1645379616, - "narHash": "sha256-eLzR3MRS9hcNqSWZxP6BP7xiBjgC3/pB5n2Q0lLFe/g=", + "lastModified": 1646162891, + "narHash": "sha256-Yoyur5LD3nRKFZRwVi2lHZi2HKoWUJFAHgIFcYsRhho=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "40ef692a55b188b1f5ae3967f3fc7808838c3f1d", + "rev": "b099eaa0e01a45fc3459bbe987c3405c425ef05c", "type": "github" }, "original": { From af1b6d8d330fe710aacf11df051c5dc3f99b9839 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Sat, 5 Mar 2022 10:28:27 +0800 Subject: [PATCH 122/352] embedding_map: avoid key 0 Object key 0 is reserved for builtin exceptions. --- artiq/language/embedding_map.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/language/embedding_map.py b/artiq/language/embedding_map.py index 3ff224b67..e98aa0252 100644 --- a/artiq/language/embedding_map.py +++ b/artiq/language/embedding_map.py @@ -39,7 +39,7 @@ class EmbeddingMap: obj_id = id(obj) if obj_id in self.object_inverse_map: return self.object_inverse_map[obj_id] - key = len(self.object_map) + key = len(self.object_map) + 1 self.object_map[key] = obj self.object_inverse_map[obj_id] = key return key From 5e4ae4dfd9899570fa472c3ee280cd722f8c29fe Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 5 Mar 2022 22:43:01 +0800 Subject: [PATCH 123/352] ad9910: fix int64 operations --- artiq/coredevice/ad9910.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 1d21d8686..1a24a632a 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -605,7 +605,7 @@ class AD9910: phase_mode = self.phase_mode # Align to coarse RTIO which aligns SYNC_CLK. I.e. clear fine TSC # This will not cause a collision or sequence error. - at_mu(now_mu() & int64(~7)) + at_mu(now_mu() & ~int64(7)) if phase_mode != PHASE_MODE_CONTINUOUS: # Auto-clear phase accumulator on IO_UPDATE. # This is active already for the next IO_UPDATE @@ -632,7 +632,7 @@ class AD9910: self.set_pow(pow_) delay_mu(int64(self.sync_data.io_update_delay)) self.cpld.io_update.pulse_mu(int64(8)) # assumes 8 mu > t_SYN_CCLK - at_mu(now_mu() & int64(~7)) # clear fine TSC again + at_mu(now_mu() & ~int64(7)) # clear fine TSC again if phase_mode != PHASE_MODE_CONTINUOUS: self.set_cfr1() # future IO_UPDATE will activate @@ -1108,7 +1108,7 @@ class AD9910: # dFTW = 1, (work around negative slope) self.write64(_AD9910_REG_RAMP_STEP, -1, 0) # delay io_update after RTIO edge - t = now_mu() + int64(8) & int64(~7) + t = now_mu() + int64(8) & ~int64(7) at_mu(t + delay_start) # assumes a maximum t_SYNC_CLK period self.cpld.io_update.pulse_mu(int64(16) - delay_start) # realign From c9fbb7024c5fcf545c501792a89307b71117ba58 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 5 Mar 2022 22:43:25 +0800 Subject: [PATCH 124/352] artiq_flash: fix bit2bin --- artiq/frontend/artiq_flash.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index a4892924f..4c8d30ca3 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -275,10 +275,7 @@ def main(): def convert_gateware(bit_filename): bin_handle, bin_filename = tempfile.mkstemp( prefix="artiq_", suffix="_" + os.path.basename(bit_filename)) - with open(bit_filename, "rb") as bit_file, \ - open(bin_handle, "wb") as bin_file: - if header: - bin_file.write(b"\x00"*8) + with open(bit_filename, "rb") as bit_file, open(bin_handle, "wb") as bin_file: bit2bin(bit_file, bin_file) atexit.register(lambda: os.unlink(bin_filename)) return bin_filename From d5806fc959f27c10d83416b6f430fc55f876af47 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 5 Mar 2022 22:44:02 +0800 Subject: [PATCH 125/352] artiq_sinara_tester: add test_ttl_in NAC3TODO --- artiq/frontend/artiq_sinara_tester.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index 81e7370f9..b6869b7d8 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -209,6 +209,7 @@ class SinaraTester(EnvExperiment): print("Testing TTL outputs: {}.".format(", ".join(name for name, dev in ttl_chunk))) self.test_ttl_out_chunk([dev for name, dev in ttl_chunk]) + # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/101 @kernel def test_ttl_in(self, ttl_out: TTLOut, ttl_in: TTLInOut) -> bool: n = 42 From a7612b973649f67f87731cf412405543e223b144 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 5 Mar 2022 22:44:25 +0800 Subject: [PATCH 126/352] artiq_sinara_tester: fix type error --- artiq/frontend/artiq_sinara_tester.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index b6869b7d8..a92eb949c 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -329,7 +329,7 @@ class SinaraTester(EnvExperiment): for channel_n, (channel_name, channel_dev) in enumerate(channels): frequency = 10*(card_n + 1) + channel_n print("{}\t{}MHz".format(channel_name, frequency)) - self.setup_urukul(channel_dev, frequency) + self.setup_urukul(channel_dev, float(frequency)) print("Press ENTER when done.") input() From 87154ea0164ff0103fcd8b87dab6c05644109a75 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 9 Mar 2022 09:15:12 +0800 Subject: [PATCH 127/352] update nac3 --- artiq/coredevice/ad9910.py | 15 --------------- artiq/coredevice/phaser.py | 8 -------- flake.lock | 8 ++++---- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 1a24a632a..708509d5e 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -15,21 +15,6 @@ from artiq.coredevice.kasli_i2c import KasliEEPROM # NAC3TODO class ValueError(Exception): pass -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/206 -@portable -def min(a: int32, b: int32) -> int32: - if a > b: - return b - else: - return a - -@portable -def max(a: int32, b: int32) -> int32: - if a > b: - return a - else: - return b - __all__ = [ "AD9910", diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index a68b5eda8..b37b0382e 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -14,14 +14,6 @@ from artiq.coredevice.trf372017 import TRF372017 class ValueError(Exception): pass -# NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/201 -@portable -def abs(x: int32) -> int32: - if x > 0: - return x - else: - return -x - PHASER_BOARD_ID = 19 PHASER_ADDR_BOARD_ID = 0x00 diff --git a/flake.lock b/flake.lock index efcd30abe..8835a0900 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1646423985, - "narHash": "sha256-WXzmupl6WNef65imDgQAvYdU0gRUu3nrbONVgYzQ+/Q=", + "lastModified": 1646753161, + "narHash": "sha256-jEq+4j90gk+oUDbCLByUhS5uGBSufcQuHMZuVZY2YGk=", "ref": "master", - "rev": "42fbe8e383bbe454e87dc2c59d8cd3cca67c42f9", - "revCount": 625, + "rev": "60b3807ab325bee3252bc0c451f0dcd5c4633ab7", + "revCount": 637, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From be3f05a4c0b9ce726dbbe83a7d237d2327725c93 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 9 Mar 2022 11:00:20 +0800 Subject: [PATCH 128/352] artiq/language/core.py: define print_rpc --- artiq/language/core.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/artiq/language/core.py b/artiq/language/core.py index b2d0f2cec..3cff29c15 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -6,6 +6,7 @@ from typing import Generic, TypeVar from functools import wraps from inspect import getfullargspec, getmodule from types import SimpleNamespace +from typing import TypeVar from math import floor, ceil from artiq.language import import_cache @@ -16,7 +17,8 @@ __all__ = [ "round64", "floor64", "ceil64", "extern", "kernel", "portable", "nac3", "rpc", "parallel", "sequential", - "set_watchdog_factory", "watchdog", "TerminationRequested" + "set_watchdog_factory", "watchdog", "TerminationRequested", + "print_rpc" ] @@ -106,6 +108,14 @@ def rpc(arg=None, flags={}): return inner_decorator return arg + +T = TypeVar('T') + +@rpc +def print_rpc(a: T): + print(a) + + @nac3 class KernelContextManager: @kernel From 1378cebe2ce859e7092c0d18722ec1e4bd8649cd Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 9 Mar 2022 11:08:46 +0800 Subject: [PATCH 129/352] drivers: use print_rpc --- artiq/coredevice/phaser.py | 6 +++--- artiq/frontend/artiq_sinara_tester.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index b37b0382e..baadd8db8 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -208,7 +208,7 @@ class Phaser: gw_rev = self.read8(PHASER_ADDR_GW_REV) if debug: - # NAC3TODO print("gw_rev:", gw_rev) + print_rpc(("gw_rev:", gw_rev)) self.core.break_realtime() self.core.delay(.1*ms) # slack @@ -288,7 +288,7 @@ class Phaser: if self.tune_fifo_offset: fifo_offset = self.dac_tune_fifo_offset() if debug: - # NAC3TODO print("fifo_offset:", fifo_offset) + print_rpc(("fifo_offset:", fifo_offset)) self.core.break_realtime() # self.dac_write(0x20, 0x0000) # stop fifo sync @@ -300,7 +300,7 @@ class Phaser: self.core.delay(.1*ms) # slack if alarms & ~0x0040 != 0: # ignore PLL alarms (see DS) if debug: - # NAC3TODO print("alarms:", alarms) + print_rpc(("alarms:", alarms)) self.core.break_realtime() # ignore alarms else: diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index a92eb949c..73de43a45 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -257,7 +257,7 @@ class SinaraTester(EnvExperiment): cpld.set_all_att_mu(test_word) readback_word = cpld.get_att_mu() if readback_word != test_word: - # NAC3TODO print(readback_word, test_word) + print_rpc((readback_word, test_word)) # NAC3TODO raise ValueError pass @@ -389,7 +389,7 @@ class SinaraTester(EnvExperiment): def almazny_set_attenuators(self, almazny: Almazny, ch: int32, atts: float): self.core.break_realtime() almazny.set_att(ch, atts) - + @kernel def almazny_toggle_output(self, almazny: Almazny, rf_on: bool): self.core.break_realtime() @@ -654,7 +654,7 @@ class SinaraTester(EnvExperiment): card_dev.input_mu(n) self.core.break_realtime() card_dev.gate_roi(0) - # NAC3TODO print("ROI sums:", n) + print_rpc(("ROI sums:", n)) def test_grabbers(self): print("*** Testing Grabber Frame Grabbers.") From 2f55f578035ca2d65a5b05eed4b1f8db85d138b9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 10 Mar 2022 17:31:02 +0800 Subject: [PATCH 130/352] update dependencies --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 8835a0900..e289af883 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1646753161, - "narHash": "sha256-jEq+4j90gk+oUDbCLByUhS5uGBSufcQuHMZuVZY2YGk=", + "lastModified": 1646904536, + "narHash": "sha256-1iyrx16xgQMjQZt2ZjqnNj5nm50gHoqdg07UGhHzsy8=", "ref": "master", - "rev": "60b3807ab325bee3252bc0c451f0dcd5c4633ab7", - "revCount": 637, + "rev": "8fd868a673ffaf89f809bacb95733ca00eba85c9", + "revCount": 641, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,11 +60,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1646162891, - "narHash": "sha256-Yoyur5LD3nRKFZRwVi2lHZi2HKoWUJFAHgIFcYsRhho=", + "lastModified": 1646588256, + "narHash": "sha256-ZHljmNlt19nSm0Mz8fx6QEhddKUkU4hhwFmfNmGn+EY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b099eaa0e01a45fc3459bbe987c3405c425ef05c", + "rev": "2ebb6c1e5ae402ba35cca5eec58385e5f1adea04", "type": "github" }, "original": { From 1a71a452259da230a2b20789c01cdac6a94470c8 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 17 Mar 2022 15:14:23 +0800 Subject: [PATCH 131/352] support builtin exceptions --- artiq/coredevice/exceptions.py | 19 ++++++++++--------- flake.lock | 8 ++++---- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 5f50b1372..29d10e4e9 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -1,5 +1,5 @@ from artiq.language.core import nac3 - +from builtins import ZeroDivisionError, ValueError, IndexError, RuntimeError, AssertionError @nac3 class RTIOUnderflow(Exception): @@ -8,7 +8,7 @@ class RTIOUnderflow(Exception): The offending event is discarded and the RTIO core keeps operating. """ - pass + artiq_builtin = True @nac3 @@ -20,7 +20,7 @@ class RTIOOverflow(Exception): read attempt and discarding some events. Reading can be reattempted after the exception is caught, and events will be partially retrieved. """ - pass + artiq_builtin = True @nac3 @@ -28,34 +28,35 @@ class RTIODestinationUnreachable(Exception): """Raised with a RTIO operation could not be completed due to a DRTIO link being down. """ - pass + artiq_builtin = True @nac3 class CacheError(Exception): """Raised when putting a value into a cache row would violate memory safety.""" - pass + artiq_builtin = True @nac3 class DMAError(Exception): """Raised when performing an invalid DMA operation.""" - pass + artiq_builtin = True @nac3 class ClockFailure(Exception): """Raised when RTIO PLL has lost lock.""" - pass + artiq_builtin = True @nac3 class I2CError(Exception): """Raised when a I2C transaction fails.""" - pass + artiq_builtin = True @nac3 class SPIError(Exception): """Raised when a SPI transaction fails.""" - pass + artiq_builtin = True + diff --git a/flake.lock b/flake.lock index e289af883..f6452e8ce 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1646904536, - "narHash": "sha256-1iyrx16xgQMjQZt2ZjqnNj5nm50gHoqdg07UGhHzsy8=", + "lastModified": 1647501180, + "narHash": "sha256-QWjv7LQRCaNjQ+PzQIs8r7moWxS/Jemaf9jzGb62L84=", "ref": "master", - "rev": "8fd868a673ffaf89f809bacb95733ca00eba85c9", - "revCount": 641, + "rev": "fb8553311cf9838156fce39bfba547c0ae099c80", + "revCount": 645, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 743b49e07ea795fc223b93bc40ad490c92576d46 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 17 Mar 2022 19:15:27 +0800 Subject: [PATCH 132/352] coredevice: remove exception workarounds --- artiq/coredevice/ad53xx.py | 6 ------ artiq/coredevice/ad9910.py | 6 ------ artiq/coredevice/ad9912.py | 6 ------ artiq/coredevice/ad9914.py | 6 ------ artiq/coredevice/adf5356.py | 7 ------- artiq/coredevice/fastino.py | 9 --------- artiq/coredevice/mirny.py | 6 ------ artiq/coredevice/phaser.py | 6 ------ artiq/coredevice/sampler.py | 7 ------- artiq/coredevice/spi2.py | 7 ------- artiq/coredevice/suservo.py | 6 ------ artiq/coredevice/urukul.py | 7 ------- 12 files changed, 79 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 080713090..26bc0d6c0 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -17,12 +17,6 @@ from artiq.coredevice.ttl import TTLOut from artiq.coredevice.spi2 import * -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass - - SPI_AD53XX_CONFIG = (0*SPI_OFFLINE | 1*SPI_END | 0*SPI_INPUT | 0*SPI_CS_POLARITY | 0*SPI_CLK_POLARITY | 1*SPI_CLK_PHASE | diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 708509d5e..23d2856f2 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -10,12 +10,6 @@ from artiq.coredevice.ttl import TTLOut from artiq.coredevice.kasli_i2c import KasliEEPROM # NAC3TODO -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass - - __all__ = [ "AD9910", "PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", "PHASE_MODE_TRACKING", diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index d8dce22e1..bd5daa78f 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -10,12 +10,6 @@ from artiq.coredevice.urukul import * from artiq.coredevice.ttl import TTLOut -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass - - @nac3 class AD9912: """ diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index 1a8abe35c..092654675 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -10,12 +10,6 @@ from artiq.coredevice.rtio import rtio_output from artiq.coredevice.core import Core -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass - - __all__ = [ "AD9914", "PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", "PHASE_MODE_TRACKING" diff --git a/artiq/coredevice/adf5356.py b/artiq/coredevice/adf5356.py index 2167ef9ad..683990bfa 100644 --- a/artiq/coredevice/adf5356.py +++ b/artiq/coredevice/adf5356.py @@ -20,13 +20,6 @@ from artiq.coredevice.spi2 import * from artiq.coredevice.adf5356_reg import * -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass - - - SPI_CONFIG = ( 0 * SPI_OFFLINE | 0 * SPI_END diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index f0ab00cc2..6e455a324 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -10,15 +10,6 @@ from artiq.language.units import ns from artiq.coredevice.core import Core -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass -@nac3 -class NotImplementedError(Exception): - pass - - @nac3 class Fastino: """Fastino 32-channel, 16-bit, 2.5 MS/s per channel streaming DAC diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py index 9ac7644ee..95247e6d2 100644 --- a/artiq/coredevice/mirny.py +++ b/artiq/coredevice/mirny.py @@ -10,12 +10,6 @@ from artiq.coredevice.core import Core from artiq.coredevice.spi2 import * -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass - - SPI_CONFIG = ( 0 * SPI_OFFLINE | 0 * SPI_END diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index b456266eb..e26a3fafe 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -9,12 +9,6 @@ from artiq.coredevice.dac34h84 import DAC34H84 from artiq.coredevice.trf372017 import TRF372017 -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass - - PHASER_BOARD_ID = 19 PHASER_ADDR_BOARD_ID = 0x00 PHASER_ADDR_HW_REV = 0x01 diff --git a/artiq/coredevice/sampler.py b/artiq/coredevice/sampler.py index 2722d12cf..686e92d62 100644 --- a/artiq/coredevice/sampler.py +++ b/artiq/coredevice/sampler.py @@ -8,13 +8,6 @@ from artiq.coredevice.spi2 import * from artiq.coredevice.ttl import TTLOut -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass - - - SPI_CONFIG = (0*SPI_OFFLINE | 0*SPI_END | 0*SPI_INPUT | 0*SPI_CS_POLARITY | 0*SPI_CLK_POLARITY | 0*SPI_CLK_PHASE | diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index 19e5ce805..4b07dc907 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -14,13 +14,6 @@ from artiq.coredevice.core import Core from artiq.coredevice.rtio import rtio_output, rtio_input_data -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass - - - __all__ = [ "SPI_DATA_ADDR", "SPI_CONFIG_ADDR", "SPI_OFFLINE", "SPI_END", "SPI_INPUT", diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 7ea8eef11..07655ba43 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -10,12 +10,6 @@ from artiq.coredevice.ad9910 import AD9910 from artiq.coredevice.sampler import adc_mu_to_volt as sampler_adc_mu_to_volt, SPI_CONFIG as SAMPLER_SPI_CONFIG, SPI_CS_PGIA as SAMPLER_SPI_CS_PGIA -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass - - COEFF_WIDTH = 18 Y_FULL_SCALE_MU = (1 << (COEFF_WIDTH - 1)) - 1 COEFF_DEPTH = 10 + 1 diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 18cc5c9d1..ab03201ec 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -8,13 +8,6 @@ from artiq.coredevice.spi2 import * from artiq.coredevice.ttl import TTLOut -# NAC3TODO work around https://git.m-labs.hk/M-Labs/nac3/issues/189 -@nac3 -class ValueError(Exception): - pass - - - SPI_CONFIG = (0 * SPI_OFFLINE | 0 * SPI_END | 0 * SPI_INPUT | 1 * SPI_CS_POLARITY | 0 * SPI_CLK_POLARITY | 0 * SPI_CLK_PHASE | From aa8dfaf0f06a58fc262a0a7c9a84fe47f78e040b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 24 Mar 2022 22:33:24 +0800 Subject: [PATCH 133/352] update NAC3 --- flake.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/flake.lock b/flake.lock index f6452e8ce..b89102281 100644 --- a/flake.lock +++ b/flake.lock @@ -11,11 +11,11 @@ ] }, "locked": { - "lastModified": 1644743100, - "narHash": "sha256-XqxMq2l2DXSovV7r2k/FXjYRM3bvVl3Mjy+C1koVAx4=", + "lastModified": 1647688999, + "narHash": "sha256-K99rYlmfCZmfam4m07hLZVg7m2zT5ul62wVGdpmjciA=", "owner": "m-labs", "repo": "artiq-comtools", - "rev": "8a126dd7d0a3f2d50ae151ec633cd52587d98796", + "rev": "7eb367b2df7510dd4fa7ccba3682b2ff64a5d982", "type": "github" }, "original": { @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1647501180, - "narHash": "sha256-QWjv7LQRCaNjQ+PzQIs8r7moWxS/Jemaf9jzGb62L84=", + "lastModified": 1648132215, + "narHash": "sha256-Sts6AGduDi4jsD6YSYR2bwHW35TByGgHAfVPrenrCxg=", "ref": "master", - "rev": "fb8553311cf9838156fce39bfba547c0ae099c80", - "revCount": 645, + "rev": "55db05fdbb2ee35a907d32de778887716f71f5fe", + "revCount": 680, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,11 +60,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1646588256, - "narHash": "sha256-ZHljmNlt19nSm0Mz8fx6QEhddKUkU4hhwFmfNmGn+EY=", + "lastModified": 1647992509, + "narHash": "sha256-AG40Nt5OWz0LBs5p457emOuwLKOvTtcv/2fUdnEN3Ws=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2ebb6c1e5ae402ba35cca5eec58385e5f1adea04", + "rev": "d2caa9377539e3b5ff1272ac3aa2d15f3081069f", "type": "github" }, "original": { @@ -92,11 +92,11 @@ ] }, "locked": { - "lastModified": 1644649772, - "narHash": "sha256-LE9L5bDSunCPEnuf5Ed8enTAXA2vkTSmjvqPX9ILO0Y=", + "lastModified": 1647688038, + "narHash": "sha256-IceTSKu1sQB8sFmDTzvmurlEHWL1cV29N0mUY5F7vUY=", "owner": "m-labs", "repo": "sipyco", - "rev": "8e4382352bc64bd01c9db35d9c9b0ef42b8b9d3b", + "rev": "1a9a3062451f5c5b125b006d1b9bee997f986abd", "type": "github" }, "original": { From 457f3c72ce2edc33c1ea4dd8dc263a291360429b Mon Sep 17 00:00:00 2001 From: pca006132 Date: Fri, 25 Mar 2022 23:42:24 +0800 Subject: [PATCH 134/352] coredevice/comm_kernel: implement attributes writeback --- artiq/coredevice/comm_kernel.py | 13 ++++++++++++- artiq/language/embedding_map.py | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 8bb8305d8..77f1ed74d 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -6,6 +6,7 @@ import socket import re import linecache import os +import json from enum import Enum from fractions import Fraction from collections import namedtuple @@ -657,7 +658,17 @@ class CommKernel: return_tags = self._read_bytes() if service_id == 0: - def service(obj, attr, value): return setattr(obj, attr, value) + def service(header, *values): + counter = 0 + for obj in json.loads(header): + old_val = embedding_map.globals_map[obj["id"]] + if "fields" in obj: + for name in obj["fields"]: + setattr(old_val, name, values[counter]) + counter += 1 + else: + old_val[:] = values[counter] + counter += 1 else: service = embedding_map.retrieve_function(service_id) logger.debug("rpc service: [%d]%r%s %r %r -> %s", service_id, service, diff --git a/artiq/language/embedding_map.py b/artiq/language/embedding_map.py index e98aa0252..6c323e7a4 100644 --- a/artiq/language/embedding_map.py +++ b/artiq/language/embedding_map.py @@ -9,6 +9,7 @@ class EmbeddingMap: self.string_map = {} self.string_reverse_map = {} self.function_map = {} + self.globals_map = {} # preallocate exception names # must be kept in sync with EXCEPTION_ID_LOOKUP in artiq/firmware/ksupport/eh_artiq.rs, From a4c1f8a079dc33c091d7ebcce3b84c98a7abb68f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 15:27:49 +0800 Subject: [PATCH 135/352] firmware: add UnwrapNoneError exception --- artiq/firmware/ksupport/eh_artiq.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/ksupport/eh_artiq.rs b/artiq/firmware/ksupport/eh_artiq.rs index e782f783c..0d6113938 100644 --- a/artiq/firmware/ksupport/eh_artiq.rs +++ b/artiq/firmware/ksupport/eh_artiq.rs @@ -344,7 +344,8 @@ static EXCEPTION_ID_LOOKUP: [(&str, u32); 10] = [ ("CacheError", 6), ("SPIError", 7), ("ZeroDivisionError", 8), - ("IndexError", 9) + ("IndexError", 9), + ("UnwrapNoneError", 10), ]; pub fn get_exception_id(name: &str) -> u32 { From d2add0a683db749808769fbe13f29d499395ca89 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 16:00:49 +0800 Subject: [PATCH 136/352] update NAC3, define option type --- artiq/coredevice/exceptions.py | 3 ++- artiq/language/core.py | 46 ++++++++++++++++++++++++++++++--- artiq/language/embedding_map.py | 3 ++- flake.lock | 8 +++--- 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 29d10e4e9..8afc444a7 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -1,6 +1,7 @@ -from artiq.language.core import nac3 +from artiq.language.core import nac3, UnwrapNoneError from builtins import ZeroDivisionError, ValueError, IndexError, RuntimeError, AssertionError + @nac3 class RTIOUnderflow(Exception): """Raised when the CPU or DMA core fails to submit a RTIO event early diff --git a/artiq/language/core.py b/artiq/language/core.py index 3cff29c15..0e66cdb54 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -6,7 +6,6 @@ from typing import Generic, TypeVar from functools import wraps from inspect import getfullargspec, getmodule from types import SimpleNamespace -from typing import TypeVar from math import floor, ceil from artiq.language import import_cache @@ -16,9 +15,10 @@ __all__ = [ "Kernel", "KernelInvariant", "virtual", "round64", "floor64", "ceil64", "extern", "kernel", "portable", "nac3", "rpc", + "print_rpc", + "Option", "Some", "none", "UnwrapNoneError", "parallel", "sequential", "set_watchdog_factory", "watchdog", "TerminationRequested", - "print_rpc" ] @@ -109,13 +109,51 @@ def rpc(arg=None, flags={}): return arg -T = TypeVar('T') - @rpc def print_rpc(a: T): print(a) +@nac3 +class UnwrapNoneError(Exception): + """Raised when unwrapping a none Option.""" + artiq_builtin = True + +class Option(Generic[T]): + _nac3_option: T + + def __init__(self, v: T): + self._nac3_option = v + + def is_none(self): + return self._nac3_option is None + + def is_some(self): + return self._nac3_option is not None + + def unwrap(self): + if self.is_none(): + raise UnwrapNoneError() + return self._nac3_option + + def __repr__(self) -> str: + if self.is_none(): + return "none" + else: + return "Some({})".format(repr(self._nac3_option)) + + def __str__(self) -> str: + if self.is_none(): + return "none" + else: + return "Some({})".format(str(self._nac3_option)) + +def Some(v: T) -> Option[T]: + return Option(v) + +none = Option(None) + + @nac3 class KernelContextManager: @kernel diff --git a/artiq/language/embedding_map.py b/artiq/language/embedding_map.py index 6c323e7a4..64a041a6f 100644 --- a/artiq/language/embedding_map.py +++ b/artiq/language/embedding_map.py @@ -23,7 +23,8 @@ class EmbeddingMap: "CacheError", "SPIError", "0:ZeroDivisionError", - "0:IndexError"]) + "0:IndexError", + "0:UnwrapNoneError"]) def preallocate_runtime_exception_names(self, names): for i, name in enumerate(names): diff --git a/flake.lock b/flake.lock index b89102281..b75e5f65e 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1648132215, - "narHash": "sha256-Sts6AGduDi4jsD6YSYR2bwHW35TByGgHAfVPrenrCxg=", + "lastModified": 1648280781, + "narHash": "sha256-HSelJSl7Q4LNI1cCApsUULidDCnRcXRocT+/e31iHL8=", "ref": "master", - "rev": "55db05fdbb2ee35a907d32de778887716f71f5fe", - "revCount": 680, + "rev": "1ad4b0227c87736beec62d94161291b7e27de6cc", + "revCount": 685, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 317c257778edbbda1b0d87426379368e0126de0b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 16:01:03 +0800 Subject: [PATCH 137/352] examples: work around NAC3 segfault --- artiq/examples/nac3devices/nac3devices.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index caf65abae..c76c4a09a 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -31,7 +31,7 @@ class NAC3Devices(EnvExperiment): ttl0_counter: KernelInvariant[EdgeCounter] grabber0: KernelInvariant[Grabber] fastino0: KernelInvariant[Fastino] - phaser0: KernelInvariant[Phaser] + # NAC3TODO segfault phaser0: KernelInvariant[Phaser] def build(self): self.setattr_device("core") @@ -48,7 +48,7 @@ class NAC3Devices(EnvExperiment): self.setattr_device("ttl0_counter") self.setattr_device("grabber0") self.setattr_device("fastino0") - self.setattr_device("phaser0") + # NAC3TODO segfault self.setattr_device("phaser0") @kernel def run(self): From 72a6ff6e9c2fc899decea87609e377890976c65e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 17:23:13 +0800 Subject: [PATCH 138/352] urukul: make RF switch TTL optional --- artiq/coredevice/ad9910.py | 7 ++++--- artiq/coredevice/ad9912.py | 9 +++++---- artiq/examples/nac3devices/nac3devices.py | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 23d2856f2..f8d0e1ff4 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -158,7 +158,7 @@ class AD9910: ftw_per_hz: KernelInvariant[float] sysclk_per_mu: KernelInvariant[int32] sysclk: KernelInvariant[float] - sw: KernelInvariant[TTLOut] + sw: KernelInvariant[Option[TTLOut]] sync_data: KernelInvariant[SyncDataUser] phase_mode: Kernel[int32] @@ -175,8 +175,9 @@ class AD9910: assert 3 <= chip_select <= 7 self.chip_select = chip_select if sw_device: - self.sw = dmgr.get(sw_device) - # NAC3TODO: support no sw + self.sw = Some(dmgr.get(sw_device)) + else: + self.sw = none clk = self.cpld.refclk / [4, 1, 2, 4][self.cpld.clk_div] self.pll_en = pll_en self.pll_n = pll_n diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index bd5daa78f..5a4af26b2 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -1,6 +1,6 @@ from numpy import int32, int64 -from artiq.language.core import KernelInvariant, nac3, kernel, portable +from artiq.language.core import * from artiq.language.units import ms, us, ns from artiq.coredevice.ad9912_reg import * @@ -35,7 +35,7 @@ class AD9912: chip_select: KernelInvariant[int32] pll_n: KernelInvariant[int32] ftw_per_hz: KernelInvariant[float] - sw: KernelInvariant[TTLOut] + sw: KernelInvariant[Option[TTLOut]] def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, pll_n=10): @@ -45,8 +45,9 @@ class AD9912: assert 4 <= chip_select <= 7 self.chip_select = chip_select if sw_device: - self.sw = dmgr.get(sw_device) - # NAC3TODO: support no sw + self.sw = Some(dmgr.get(sw_device)) + else: + self.sw = none self.pll_n = pll_n sysclk = self.cpld.refclk / [1, 1, 2, 4][self.cpld.clk_div] * pll_n assert sysclk <= 1e9 diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index c76c4a09a..7bc98738b 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -67,7 +67,7 @@ class NAC3Devices(EnvExperiment): self.core.break_realtime() self.urukul0_cpld.init() self.urukul0_ch0.init() - self.urukul0_ch0.sw.on() + self.urukul0_ch0.sw.unwrap().on() for i in range(10): self.urukul0_ch0.set((10. + float(i))*MHz) self.urukul0_ch0.set_att(6.) From bd3ab50a09dad709e7627bc5ca21382686f1eeba Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 17:41:18 +0800 Subject: [PATCH 139/352] ad9910: cleanup import --- artiq/coredevice/ad9910.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index f8d0e1ff4..3d6f882c5 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -5,7 +5,6 @@ from artiq.language.units import us, ms from artiq.coredevice.spi2 import * from artiq.coredevice.urukul import * -from artiq.coredevice.urukul import * from artiq.coredevice.ttl import TTLOut from artiq.coredevice.kasli_i2c import KasliEEPROM # NAC3TODO From 6aec42383822017bffcd1c2181ba6a89fcdb1025 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Sat, 26 Mar 2022 19:22:39 +0800 Subject: [PATCH 140/352] coredevice/comm_kernel: attributes writeback update --- artiq/coredevice/comm_kernel.py | 6 +++--- artiq/language/embedding_map.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 77f1ed74d..670d2cc41 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -658,10 +658,10 @@ class CommKernel: return_tags = self._read_bytes() if service_id == 0: - def service(header, *values): + def service(*values): counter = 0 - for obj in json.loads(header): - old_val = embedding_map.globals_map[obj["id"]] + for obj in embedding_map.attributes_writeback: + old_val = obj["obj"] if "fields" in obj: for name in obj["fields"]: setattr(old_val, name, values[counter]) diff --git a/artiq/language/embedding_map.py b/artiq/language/embedding_map.py index 64a041a6f..466426121 100644 --- a/artiq/language/embedding_map.py +++ b/artiq/language/embedding_map.py @@ -9,7 +9,7 @@ class EmbeddingMap: self.string_map = {} self.string_reverse_map = {} self.function_map = {} - self.globals_map = {} + self.attributes_writeback = [] # preallocate exception names # must be kept in sync with EXCEPTION_ID_LOOKUP in artiq/firmware/ksupport/eh_artiq.rs, From 5c70b97850a6f42656da826ca8704367ee0b31b4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 20:09:11 +0800 Subject: [PATCH 141/352] runtime: fix EXCEPTION_ID_LOOKUP --- artiq/firmware/ksupport/eh_artiq.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/ksupport/eh_artiq.rs b/artiq/firmware/ksupport/eh_artiq.rs index 0d6113938..d69608e9d 100644 --- a/artiq/firmware/ksupport/eh_artiq.rs +++ b/artiq/firmware/ksupport/eh_artiq.rs @@ -334,7 +334,7 @@ extern fn stop_fn(_version: c_int, } // Must be kept in sync with preallocate_runtime_exception_names() in artiq/language/embedding_map.py -static EXCEPTION_ID_LOOKUP: [(&str, u32); 10] = [ +static EXCEPTION_ID_LOOKUP: [(&str, u32); 11] = [ ("RuntimeError", 0), ("RTIOUnderflow", 1), ("RTIOOverflow", 2), From 8e5fc599eb8029b64bf2a3b2d4fd285aea95f37b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 20:20:50 +0800 Subject: [PATCH 142/352] update NAC3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index b75e5f65e..8e223b2ed 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1648280781, - "narHash": "sha256-HSelJSl7Q4LNI1cCApsUULidDCnRcXRocT+/e31iHL8=", + "lastModified": 1648296838, + "narHash": "sha256-vAgeuLY4CYW9O3a2uM9UOQxdrN8M/4wlzkh87tEzVQ8=", "ref": "master", - "rev": "1ad4b0227c87736beec62d94161291b7e27de6cc", - "revCount": 685, + "rev": "bf067e248186eba735d54f485cf92b4578daf1d4", + "revCount": 688, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 2bc770ec72f0b03b258e277d3541eca8223fdd0a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 20:21:01 +0800 Subject: [PATCH 143/352] Revert "examples: work around NAC3 segfault" This reverts commit 317c257778edbbda1b0d87426379368e0126de0b. --- artiq/examples/nac3devices/nac3devices.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index 7bc98738b..6452154b0 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -31,7 +31,7 @@ class NAC3Devices(EnvExperiment): ttl0_counter: KernelInvariant[EdgeCounter] grabber0: KernelInvariant[Grabber] fastino0: KernelInvariant[Fastino] - # NAC3TODO segfault phaser0: KernelInvariant[Phaser] + phaser0: KernelInvariant[Phaser] def build(self): self.setattr_device("core") @@ -48,7 +48,7 @@ class NAC3Devices(EnvExperiment): self.setattr_device("ttl0_counter") self.setattr_device("grabber0") self.setattr_device("fastino0") - # NAC3TODO segfault self.setattr_device("phaser0") + self.setattr_device("phaser0") @kernel def run(self): From 0190604ba0fc8d53c8e6af9080602a666543def9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 20:22:58 +0800 Subject: [PATCH 144/352] comm_kernel: remove forgotten json import in 6aec423838 --- artiq/coredevice/comm_kernel.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 670d2cc41..7db34453c 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -6,7 +6,6 @@ import socket import re import linecache import os -import json from enum import Enum from fractions import Fraction from collections import namedtuple From 0233e50d47fb45d22054879eea18478269c7d3c4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 20:41:37 +0800 Subject: [PATCH 145/352] coredevice: fix execution of several kernels with attribute writeback --- artiq/coredevice/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 8b55bd629..55aa598ee 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -57,7 +57,6 @@ class Core: self.comm.core = self self.target = target self.compiler = nac3artiq.NAC3(target) - self.embedding_map = EmbeddingMap() def close(self): self.comm.close() @@ -80,7 +79,8 @@ class Core: self.compiler.compile_method_to_file(obj, name, args, file_output, embedding_map) def run(self, function, args, kwargs): - kernel_library = self.compile(function, args, kwargs, self.embedding_map) + embedding_map = EmbeddingMap() + kernel_library = self.compile(function, args, kwargs, embedding_map) if self.first_run: self.comm.check_system_info() self.first_run = False @@ -89,7 +89,7 @@ class Core: self.comm.load(kernel_library) self.comm.run() - self.comm.serve(self.embedding_map, symbolizer) + self.comm.serve(embedding_map, symbolizer) @portable def seconds_to_mu(self, seconds: float) -> int64: From ec8ee1e9346d43b2d93a69c4b47cc4972e83ad7b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 20:42:21 +0800 Subject: [PATCH 146/352] language: clean up EmbeddingMap --- artiq/language/__init__.py | 2 -- artiq/language/embedding_map.py | 6 ------ 2 files changed, 8 deletions(-) diff --git a/artiq/language/__init__.py b/artiq/language/__init__.py index 145471752..99c019a75 100644 --- a/artiq/language/__init__.py +++ b/artiq/language/__init__.py @@ -3,7 +3,6 @@ from artiq.language.core import * from artiq.language.environment import * from artiq.language.units import * from artiq.language.scan import * -from artiq.language.embedding_map import * from . import import_cache __all__ = ["import_cache"] @@ -11,4 +10,3 @@ __all__.extend(core.__all__) __all__.extend(environment.__all__) __all__.extend(units.__all__) __all__.extend(scan.__all__) -__all__.extend(embedding_map.__all__) diff --git a/artiq/language/embedding_map.py b/artiq/language/embedding_map.py index 466426121..050925db9 100644 --- a/artiq/language/embedding_map.py +++ b/artiq/language/embedding_map.py @@ -1,7 +1,3 @@ -__all__ = [ - 'EmbeddingMap' -] - class EmbeddingMap: def __init__(self): self.object_inverse_map = {} @@ -62,5 +58,3 @@ class EmbeddingMap: def retrieve_str(self, key): return self.string_map[key] - - From 8ea6a46ee6c411b71022edb4e1263cfd16018787 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 26 Mar 2022 21:32:26 +0800 Subject: [PATCH 147/352] update NAC3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 8e223b2ed..bc4762ac7 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1648296838, - "narHash": "sha256-vAgeuLY4CYW9O3a2uM9UOQxdrN8M/4wlzkh87tEzVQ8=", + "lastModified": 1648300212, + "narHash": "sha256-Qp6CIMh/0oP9XDm53Az77DXl5dV5M0IWR2QTWVlbUkg=", "ref": "master", - "rev": "bf067e248186eba735d54f485cf92b4578daf1d4", - "revCount": 688, + "rev": "e4581a6d9bb87e517951d77e69bf3f1025bc311e", + "revCount": 690, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 9d26f887ee16d63290597ab7995d3ab28c764c3d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Mar 2022 17:53:51 +0800 Subject: [PATCH 148/352] update NAC3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index bc4762ac7..563e227e5 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1648300212, - "narHash": "sha256-Qp6CIMh/0oP9XDm53Az77DXl5dV5M0IWR2QTWVlbUkg=", + "lastModified": 1648348280, + "narHash": "sha256-zPotCWV0l1EgxJp/1MIUNvhCiMoEmpn5fnARrLNa6Ak=", "ref": "master", - "rev": "e4581a6d9bb87e517951d77e69bf3f1025bc311e", - "revCount": 690, + "rev": "bed33a7421b2c8f6b595f8feaa602de041bcc14f", + "revCount": 695, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 1a3607564b921d8b76b715d93a1830ad75b6c4d8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Mar 2022 18:02:36 +0800 Subject: [PATCH 149/352] urukul: support dds_reset and sync options --- artiq/coredevice/urukul.py | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index ab03201ec..d28dff76c 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -1,11 +1,11 @@ from numpy import int32, int64 -from artiq.language.core import nac3, Kernel, KernelInvariant, kernel, portable +from artiq.language.core import * from artiq.language.units import us, ms from artiq.coredevice.core import Core from artiq.coredevice.spi2 import * -from artiq.coredevice.ttl import TTLOut +from artiq.coredevice.ttl import TTLOut, TTLClockGen SPI_CONFIG = (0 * SPI_OFFLINE | 0 * SPI_END | @@ -104,15 +104,6 @@ def urukul_sta_proto_rev(sta: int32) -> int32: """Return the PROTO_REV value from Urukul status register value.""" return (sta >> STA_PROTO_REV) & 0x7f -@nac3 -class _DummySync: - def __init__(self, cpld): - self.cpld = cpld - - @kernel - def set_mu(self, ftw: int32): - pass - @nac3 class CPLD: @@ -159,7 +150,8 @@ class CPLD: bus: KernelInvariant[SPIMaster] io_update: KernelInvariant[TTLOut] clk_div: KernelInvariant[int32] - sync: KernelInvariant[_DummySync] + dds_reset: KernelInvariant[Option[TTLOut]] + sync: KernelInvariant[Option[TTLClockGen]] cfg_reg: Kernel[int32] att_reg: Kernel[int32] sync_div: Kernel[int32] @@ -183,15 +175,15 @@ class CPLD: # NAC3TODO raise NotImplementedError if dds_reset_device is not None: - self.dds_reset = dmgr.get(dds_reset_device) + self.dds_reset = Some(dmgr.get(dds_reset_device)) + else: + self.dds_reset = none if sync_device is not None: - self.sync = dmgr.get(sync_device) + self.sync = Some(dmgr.get(sync_device)) if sync_div is None: sync_div = 2 - # NAC3TODO - raise NotImplementedError else: - self.sync = _DummySync(self) + self.sync = none assert sync_div is None sync_div = 0 @@ -420,7 +412,8 @@ class CPLD: ftw_max = 1 << 4 ftw = ftw_max // div # NAC3TODO assert ftw * div == ftw_max - self.sync.set_mu(ftw) + if self.sync.is_some(): + self.sync.unwrap().set_mu(ftw) @kernel def set_profile(self, profile: int32): From b1cfd343eb7c0362337ff9633be086f7ec84c5a2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 29 Mar 2022 08:49:43 +0800 Subject: [PATCH 150/352] update NAC3 --- artiq/coredevice/ad53xx.py | 4 ++-- artiq/coredevice/ad9912.py | 8 ++++---- artiq/coredevice/fastino.py | 2 +- artiq/coredevice/urukul.py | 2 +- flake.lock | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 26bc0d6c0..293776b1c 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -381,8 +381,8 @@ class AD53xx: gain_err = voltage_to_mu(vfs, self.offset_dacs, self.vref) - ( offset_err + 0xffff) - # NAC3TODO assert offset_err <= 0 - # NAC3TODO assert gain_err >= 0 + assert offset_err <= 0 + assert gain_err >= 0 self.core.break_realtime() self.write_offset_mu(channel, 0x8000-offset_err) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 5a4af26b2..7f81ef400 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -62,8 +62,8 @@ class AD9912: :param data: Data to be written: int32 :param length: Length in bytes (1-4) """ - # NAC3TODO assert length > 0 - # NAC3TODO assert length <= 4 + assert length > 0 + assert length <= 4 self.bus.set_config_mu(SPI_CONFIG, 16, SPIT_DDS_WR, self.chip_select) self.bus.write((addr | ((length - 1) << 13)) << 16) @@ -80,8 +80,8 @@ class AD9912: :param length: Length in bytes (1-4) :return: Data read """ - # NAC3TODO assert length > 0 - # NAC3TODO assert length <= 4 + assert length > 0 + assert length <= 4 self.bus.set_config_mu(SPI_CONFIG, 16, SPIT_DDS_WR, self.chip_select) self.bus.write((addr | ((length - 1) << 13) | 0x8000) << 16) diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index 6e455a324..995d20b6b 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -274,7 +274,7 @@ class Fastino: while gain > 1 << gain_exponent: gain_exponent += 1 gain_exponent += order*rate_exponent - # NAC3TODO assert gain_exponent <= order*16 + assert gain_exponent <= order*16 self.stage_cic_mu(rate_mantissa - 1, rate_exponent, gain_exponent) return rate_mantissa << rate_exponent diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index d28dff76c..769c31ab3 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -411,7 +411,7 @@ class CPLD: """ ftw_max = 1 << 4 ftw = ftw_max // div - # NAC3TODO assert ftw * div == ftw_max + assert ftw * div == ftw_max if self.sync.is_some(): self.sync.unwrap().set_mu(ftw) diff --git a/flake.lock b/flake.lock index 563e227e5..c8e23be43 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1648348280, - "narHash": "sha256-zPotCWV0l1EgxJp/1MIUNvhCiMoEmpn5fnARrLNa6Ak=", + "lastModified": 1648508200, + "narHash": "sha256-8ohq5rj5rV9xyHDbU0oT/2CXT917XQYtxU92GIC+43s=", "ref": "master", - "rev": "bed33a7421b2c8f6b595f8feaa602de041bcc14f", - "revCount": 695, + "rev": "a38cc0444456392fba6949367e4073ee9df149bf", + "revCount": 705, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 34f386255812d23094a9d6ee219610c5e4fec424 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Mar 2022 08:43:08 +0800 Subject: [PATCH 151/352] update NAC3 --- artiq/coredevice/ad53xx.py | 9 +++++---- artiq/examples/nac3devices/nac3devices.py | 2 +- flake.lock | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 293776b1c..9d746fed3 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -10,7 +10,7 @@ time is an error. from numpy import int32, int64 -from artiq.language.core import nac3, kernel, portable, Kernel, KernelInvariant +from artiq.language.core import * from artiq.language.units import ns, us from artiq.coredevice.core import Core from artiq.coredevice.ttl import TTLOut @@ -313,7 +313,7 @@ class AD53xx: self.ldac.on() @kernel - def set_dac_mu(self, values: list[int32], channels: list[int32]): # NAC3TODO default list(range(40)) + def set_dac_mu(self, values: list[int32], channels: Option[list[int32]] = none): """Program multiple DAC channels and pulse LDAC to update the DAC outputs. @@ -335,14 +335,15 @@ class AD53xx: t_10 = self.core.seconds_to_mu(1500.*ns) # compensate all delays that will be applied delay_mu(-t_10-int64(len(values))*self.bus.xfer_duration_mu) + channels_list = channels.unwrap() if channels.is_some() else [i for i in range(40)] for i in range(len(values)): - self.write_dac_mu(channels[i], values[i]) + self.write_dac_mu(channels_list[i], values[i]) delay_mu(t_10) self.load() at_mu(t0) @kernel - def set_dac(self, voltages: list[float], channels: list[int32]): # NAC3TODO default list(range(40)) + def set_dac(self, voltages: list[float], channels: Option[list[int32]] = none): """Program multiple DAC channels and pulse LDAC to update the DAC outputs. diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index 6452154b0..b64efe27b 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -55,7 +55,7 @@ class NAC3Devices(EnvExperiment): self.core.reset() self.zotino0.init() self.zotino0.set_leds(0x15) - self.zotino0.set_dac([1.2, -5.3, 3.4, 4.5], [0, 1, 2, 3]) + self.zotino0.set_dac([1.2, -5.3, 3.4, 4.5]) self.core.break_realtime() self.mirny0_cpld.init() diff --git a/flake.lock b/flake.lock index c8e23be43..fbfcb7521 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1648508200, - "narHash": "sha256-8ohq5rj5rV9xyHDbU0oT/2CXT917XQYtxU92GIC+43s=", + "lastModified": 1648584347, + "narHash": "sha256-m27UgTuWDO6rLkwNdxBeGXW7rLZbdl5vCp7afe0P4qo=", "ref": "master", - "rev": "a38cc0444456392fba6949367e4073ee9df149bf", - "revCount": 705, + "rev": "b8ef44d64eabf62175d2b3e900124e0607c7b4d3", + "revCount": 710, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 724fc62925c88269350a93db208d0a4b4da3aa48 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 10:12:15 +0800 Subject: [PATCH 152/352] setup.py: stop checking for dependencies --- setup.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/setup.py b/setup.py index 60304d724..b43d3a6f1 100755 --- a/setup.py +++ b/setup.py @@ -10,16 +10,6 @@ if sys.version_info[:2] < (3, 9): raise Exception("You need Python 3.9+") -# Depends on PyQt5, but setuptools cannot check for it. -requirements = [ - "numpy", "scipy", - "python-dateutil", "prettytable", "h5py", - "qasync", "pyqtgraph", "pygit2", - # FIXME: figure out how to get the setuptools crap to find nac3artiq. Python imports it just fine. - # See: https://github.com/PyO3/setuptools-rust - # Alternatively, stop using setuptools, it sucks. -] - console_scripts = [ "artiq_client = artiq.frontend.artiq_client:main", "artiq_compile = artiq.frontend.artiq_compile:main", @@ -66,8 +56,6 @@ Programming Language :: Python :: 3.9 Topic :: Scientific/Engineering :: Physics Topic :: System :: Hardware """.splitlines(), - install_requires=requirements, - extras_require={}, packages=find_packages(), namespace_packages=[], include_package_data=True, From a4bdc6c9cb00f5086921e5e8b0065c0c06abfc09 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 10:12:29 +0800 Subject: [PATCH 153/352] build MSYS2 packages --- flake.lock | 26 +++++++++---------- flake.nix | 5 ++++ windows/PKGBUILD.artiq | 8 ++++++ windows/PKGBUILD.artiq-comtools | 8 ++++++ windows/PKGBUILD.common | 19 ++++++++++++++ windows/PKGBUILD.sipyco | 8 ++++++ windows/default.nix | 46 +++++++++++++++++++++++++++++++++ windows/makepkg.conf | 2 ++ 8 files changed, 109 insertions(+), 13 deletions(-) create mode 100644 windows/PKGBUILD.artiq create mode 100644 windows/PKGBUILD.artiq-comtools create mode 100644 windows/PKGBUILD.common create mode 100644 windows/PKGBUILD.sipyco create mode 100644 windows/default.nix create mode 100644 windows/makepkg.conf diff --git a/flake.lock b/flake.lock index fbfcb7521..132cbbba8 100644 --- a/flake.lock +++ b/flake.lock @@ -11,11 +11,11 @@ ] }, "locked": { - "lastModified": 1647688999, - "narHash": "sha256-K99rYlmfCZmfam4m07hLZVg7m2zT5ul62wVGdpmjciA=", + "lastModified": 1649124276, + "narHash": "sha256-l1+vk7cvj4cjl83wRx/y1Jwdds4e8xAzpxHrXusEZ5A=", "owner": "m-labs", "repo": "artiq-comtools", - "rev": "7eb367b2df7510dd4fa7ccba3682b2ff64a5d982", + "rev": "e2d85f2e51ecdac463da752ef754e59572f9e119", "type": "github" }, "original": { @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1648584347, - "narHash": "sha256-m27UgTuWDO6rLkwNdxBeGXW7rLZbdl5vCp7afe0P4qo=", + "lastModified": 1649124608, + "narHash": "sha256-ZBmCeuOSZTxa9c9nbdFtSCDy940HlMAhNNh5TA42f1E=", "ref": "master", - "rev": "b8ef44d64eabf62175d2b3e900124e0607c7b4d3", - "revCount": 710, + "rev": "e05b0bf5dc427952a60b0dbe696de2ea239d9206", + "revCount": 724, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,11 +60,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1647992509, - "narHash": "sha256-AG40Nt5OWz0LBs5p457emOuwLKOvTtcv/2fUdnEN3Ws=", + "lastModified": 1649024309, + "narHash": "sha256-AWbvj/NHZXVwAnHaVOFlxg7tcNerEKrKBmgGfztSHWM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d2caa9377539e3b5ff1272ac3aa2d15f3081069f", + "rev": "af0a9bc0e5341855518e9c1734d7ef913e5138b9", "type": "github" }, "original": { @@ -92,11 +92,11 @@ ] }, "locked": { - "lastModified": 1647688038, - "narHash": "sha256-IceTSKu1sQB8sFmDTzvmurlEHWL1cV29N0mUY5F7vUY=", + "lastModified": 1649124180, + "narHash": "sha256-NxGYtKeUqvABCkCBixJ1cDJGTPooHh4I2MuWfj0i0Ok=", "owner": "m-labs", "repo": "sipyco", - "rev": "1a9a3062451f5c5b125b006d1b9bee997f986abd", + "rev": "0d61fba000d03692ee5aa66c813977e7db085c31", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 134a96551..94cd4b92d 100644 --- a/flake.nix +++ b/flake.nix @@ -336,6 +336,8 @@ }; }; + packages.x86_64-w64-mingw32 = import ./windows { inherit sipyco nac3 artiq-comtools; artiq = self; }; + inherit makeArtiqBoardPackage; defaultPackage.x86_64-linux = packages.x86_64-linux.python3-mimalloc.withPackages(ps: [ packages.x86_64-linux.artiq ]); @@ -361,6 +363,9 @@ hydraJobs = { inherit (packages.x86_64-linux) artiq artiq-board-kc705-nist_clock openocd-bscanspi; + sipyco-msys2-pkg = packages.x86_64-w64-mingw32.sipyco-pkg; + artiq-comtools-msys2-pkg = packages.x86_64-w64-mingw32.artiq-comtools-pkg; + artiq-msys2-pkg = packages.x86_64-w64-mingw32.artiq-pkg; }; }; diff --git a/windows/PKGBUILD.artiq b/windows/PKGBUILD.artiq new file mode 100644 index 000000000..6f6aefaa1 --- /dev/null +++ b/windows/PKGBUILD.artiq @@ -0,0 +1,8 @@ +pkgbase="mingw-w64-artiq" +pkgname="mingw-w64-x86_64-artiq" +pkgrel=1 +pkgdesc="A leading-edge control system for quantum information experiments" +license=("LGPL") +depends=("mingw-w64-x86_64-python") + +source PKGBUILD.common diff --git a/windows/PKGBUILD.artiq-comtools b/windows/PKGBUILD.artiq-comtools new file mode 100644 index 000000000..370c7436d --- /dev/null +++ b/windows/PKGBUILD.artiq-comtools @@ -0,0 +1,8 @@ +pkgbase="mingw-w64-artiq-comtools" +pkgname="mingw-w64-x86_64-artiq-comtools" +pkgrel=1 +pkgdesc="Lightweight ARTIQ communication tools" +license=("LGPL") +depends=("mingw-w64-x86_64-python") + +source PKGBUILD.common diff --git a/windows/PKGBUILD.common b/windows/PKGBUILD.common new file mode 100644 index 000000000..78d493e8a --- /dev/null +++ b/windows/PKGBUILD.common @@ -0,0 +1,19 @@ +arch=("any") +mingw_arch=("mingw64") +pkgver=${DRV_VERSION} +url="https://m-labs.hk" +source=("source.tar") +sha256sums=("SKIP") + +build() { + mkdir mingw64 + export PYTHONPATH=`pwd`/mingw64/lib/python3.9/site-packages + chmod +w -R source + cd source + wine-msys2-build python setup.py install --prefix=../mingw64 + cd .. +} + +package() { + cp -R mingw64 ${pkgdir} +} diff --git a/windows/PKGBUILD.sipyco b/windows/PKGBUILD.sipyco new file mode 100644 index 000000000..d835bd1f3 --- /dev/null +++ b/windows/PKGBUILD.sipyco @@ -0,0 +1,8 @@ +pkgbase="mingw-w64-sipyco" +pkgname="mingw-w64-x86_64-sipyco" +pkgrel=1 +pkgdesc="Simple Python Communications" +license=("LGPL") +depends=("mingw-w64-x86_64-python") + +source PKGBUILD.common diff --git a/windows/default.nix b/windows/default.nix new file mode 100644 index 000000000..7d56e5c99 --- /dev/null +++ b/windows/default.nix @@ -0,0 +1,46 @@ +{ sipyco, nac3, artiq-comtools, artiq }: +let + pkgs = import nac3.inputs.nixpkgs { system = "x86_64-linux"; }; + makeMsys2 = { name, version, src }: pkgs.stdenvNoCC.mkDerivation { + pname = "${name}-msys2-pkg"; + inherit version; + nativeBuildInputs = [ + pkgs.pacman pkgs.fakeroot pkgs.libarchive pkgs.zstd pkgs.file + nac3.packages.x86_64-w64-mingw32.wine-msys2-build + ]; + inherit src; + phases = [ "buildPhase" "installPhase" ]; + buildPhase = + '' + export DRV_VERSION=${version} + ln -s ${./PKGBUILD.${name}} PKGBUILD + ln -s ${./PKGBUILD.common} PKGBUILD.common + ln -s $src source + tar cfh source.tar source + rm source + makepkg --config ${./makepkg.conf} --nodeps + ''; + installPhase = + '' + mkdir $out $out/nix-support + cp *.pkg.tar.zst $out + echo file msys2 $out/*.pkg.tar.zst >> $out/nix-support/hydra-build-products + ''; + }; +in { + sipyco-pkg = makeMsys2 { + name = "sipyco"; + src = sipyco; + inherit (sipyco.packages.x86_64-linux.sipyco) version; + }; + artiq-comtools-pkg = makeMsys2 { + name = "artiq-comtools"; + src = artiq-comtools; + inherit (artiq-comtools.packages.x86_64-linux.artiq-comtools) version; + }; + artiq-pkg = makeMsys2 { + name = "artiq"; + src = artiq; + inherit (artiq.packages.x86_64-linux.artiq) version; + }; +} diff --git a/windows/makepkg.conf b/windows/makepkg.conf new file mode 100644 index 000000000..3238344eb --- /dev/null +++ b/windows/makepkg.conf @@ -0,0 +1,2 @@ +PKGEXT='.pkg.tar.zst' +SRCEXT='.src.tar.gz' From 546c0ed2c50997ef6946fa3dc2028544ae555595 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 10:27:47 +0800 Subject: [PATCH 154/352] windows: set package dependencies --- windows/PKGBUILD.artiq | 15 ++++++++++++++- windows/PKGBUILD.artiq-comtools | 7 ++++++- windows/PKGBUILD.sipyco | 10 +++++++--- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/windows/PKGBUILD.artiq b/windows/PKGBUILD.artiq index 6f6aefaa1..be0a4a5c2 100644 --- a/windows/PKGBUILD.artiq +++ b/windows/PKGBUILD.artiq @@ -3,6 +3,19 @@ pkgname="mingw-w64-x86_64-artiq" pkgrel=1 pkgdesc="A leading-edge control system for quantum information experiments" license=("LGPL") -depends=("mingw-w64-x86_64-python") +depends=( + "mingw-w64-x86_64-python" + "mingw-w64-x86_64-python-h5py" + "mingw-w64-x86_64-python-pyqt5" + # TODO "mingw-w64-x86_64-python-qasync" + # TODO "mingw-w64-x86_64-python-pyqtgraph" + "mingw-w64-x86_64-python-numpy" + "mingw-w64-x86_64-python-scipy" + "mingw-w64-x86_64-python-dateutil" + "mingw-w64-x86_64-python-prettytable" + "mingw-w64-x86_64-python-pygit2" + "mingw-w64-x86_64-python-sipyco" + "mingw-w64-x86_64-nac3artiq" +) source PKGBUILD.common diff --git a/windows/PKGBUILD.artiq-comtools b/windows/PKGBUILD.artiq-comtools index 370c7436d..2bd5f3e64 100644 --- a/windows/PKGBUILD.artiq-comtools +++ b/windows/PKGBUILD.artiq-comtools @@ -3,6 +3,11 @@ pkgname="mingw-w64-x86_64-artiq-comtools" pkgrel=1 pkgdesc="Lightweight ARTIQ communication tools" license=("LGPL") -depends=("mingw-w64-x86_64-python") +depends=( + "mingw-w64-x86_64-python" + "mingw-w64-x86_64-python-sipyco" + "mingw-w64-x86_64-python-numpy" + "mingw-w64-x86_64-python-aiohttp" +) source PKGBUILD.common diff --git a/windows/PKGBUILD.sipyco b/windows/PKGBUILD.sipyco index d835bd1f3..dddeb4a34 100644 --- a/windows/PKGBUILD.sipyco +++ b/windows/PKGBUILD.sipyco @@ -1,8 +1,12 @@ -pkgbase="mingw-w64-sipyco" -pkgname="mingw-w64-x86_64-sipyco" +pkgbase="mingw-w64-python-sipyco" +pkgname="mingw-w64-x86_64-python-sipyco" pkgrel=1 pkgdesc="Simple Python Communications" license=("LGPL") -depends=("mingw-w64-x86_64-python") +depends=( + "mingw-w64-x86_64-python" + "mingw-w64-x86_64-python-numpy" + # TODO "mingw-w64-x86_64-python-pybase64" +) source PKGBUILD.common From 73edc01fc6673b24c3a4ea44bfb9f5745dc50d5c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 10:40:52 +0800 Subject: [PATCH 155/352] windows: create msys2 repos --- windows/default.nix | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/windows/default.nix b/windows/default.nix index 7d56e5c99..c4447526b 100644 --- a/windows/default.nix +++ b/windows/default.nix @@ -27,7 +27,7 @@ let echo file msys2 $out/*.pkg.tar.zst >> $out/nix-support/hydra-build-products ''; }; -in { +in rec { sipyco-pkg = makeMsys2 { name = "sipyco"; src = sipyco; @@ -43,4 +43,18 @@ in { src = artiq; inherit (artiq.packages.x86_64-linux.artiq) version; }; + msys2-repos = pkgs.stdenvNoCC.mkDerivation { + name = "msys2-repos"; + nativeBuildInputs = [ pkgs.pacman ]; + phases = [ "buildPhase" ]; + buildPhase = + '' + mkdir $out + cd $out + ln -s ${sipyco-pkg}/*.pkg.tar.zst . + ln -s ${artiq-comtools-pkg}/*.pkg.tar.zst . + ln -s ${artiq-pkg}/*.pkg.tar.zst . + repo-add artiq.db.tar.gz *.pkg.tar.zst + ''; + }; } From 0f09bfc3c2fa6cb9acdabbf2ccb5d956f4a54e59 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 10:48:36 +0800 Subject: [PATCH 156/352] flake: add msys2-repos to hydra --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index 94cd4b92d..f2d536582 100644 --- a/flake.nix +++ b/flake.nix @@ -366,6 +366,7 @@ sipyco-msys2-pkg = packages.x86_64-w64-mingw32.sipyco-pkg; artiq-comtools-msys2-pkg = packages.x86_64-w64-mingw32.artiq-comtools-pkg; artiq-msys2-pkg = packages.x86_64-w64-mingw32.artiq-pkg; + msys2-repos = packages.x86_64-w64-mingw32.msys2-repos; }; }; From 5bc2cf6cc2c39e0bcb4d5fdd36a8dc13bd3fcf86 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 10:55:52 +0800 Subject: [PATCH 157/352] windows: add NAC3 to MSYS2 repos --- windows/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/default.nix b/windows/default.nix index c4447526b..68b764fb0 100644 --- a/windows/default.nix +++ b/windows/default.nix @@ -53,6 +53,7 @@ in rec { cd $out ln -s ${sipyco-pkg}/*.pkg.tar.zst . ln -s ${artiq-comtools-pkg}/*.pkg.tar.zst . + ln -s ${nac3.packages.x86_64-w64-mingw32.nac3artiq-pkg}/*.pkg.tar.zst . ln -s ${artiq-pkg}/*.pkg.tar.zst . repo-add artiq.db.tar.gz *.pkg.tar.zst ''; From dfb2908d09875df653f72b2bcbf69229996f2fe5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 11:32:00 +0800 Subject: [PATCH 158/352] windows: clean up easy-install pollution --- windows/PKGBUILD.common | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/PKGBUILD.common b/windows/PKGBUILD.common index 78d493e8a..35315b21f 100644 --- a/windows/PKGBUILD.common +++ b/windows/PKGBUILD.common @@ -12,6 +12,7 @@ build() { cd source wine-msys2-build python setup.py install --prefix=../mingw64 cd .. + rm mingw64/lib/python3.9/site-packages/easy-install.pth } package() { From 64b56077cdce188b4f6613979f333e8ce94231c6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 16:26:08 +0800 Subject: [PATCH 159/352] windows: package pyqtgraph --- flake.nix | 1 + windows/PKGBUILD.artiq | 2 +- windows/PKGBUILD.common | 2 +- windows/PKGBUILD.pyqtgraph | 11 +++++++++++ windows/default.nix | 6 ++++++ 5 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 windows/PKGBUILD.pyqtgraph diff --git a/flake.nix b/flake.nix index f2d536582..f153e52fe 100644 --- a/flake.nix +++ b/flake.nix @@ -363,6 +363,7 @@ hydraJobs = { inherit (packages.x86_64-linux) artiq artiq-board-kc705-nist_clock openocd-bscanspi; + pyqtgraph-msys2-pkg = packages.x86_64-w64-mingw32.pyqtgraph-pkg; sipyco-msys2-pkg = packages.x86_64-w64-mingw32.sipyco-pkg; artiq-comtools-msys2-pkg = packages.x86_64-w64-mingw32.artiq-comtools-pkg; artiq-msys2-pkg = packages.x86_64-w64-mingw32.artiq-pkg; diff --git a/windows/PKGBUILD.artiq b/windows/PKGBUILD.artiq index be0a4a5c2..28dbd4913 100644 --- a/windows/PKGBUILD.artiq +++ b/windows/PKGBUILD.artiq @@ -8,7 +8,7 @@ depends=( "mingw-w64-x86_64-python-h5py" "mingw-w64-x86_64-python-pyqt5" # TODO "mingw-w64-x86_64-python-qasync" - # TODO "mingw-w64-x86_64-python-pyqtgraph" + "mingw-w64-x86_64-python-pyqtgraph" "mingw-w64-x86_64-python-numpy" "mingw-w64-x86_64-python-scipy" "mingw-w64-x86_64-python-dateutil" diff --git a/windows/PKGBUILD.common b/windows/PKGBUILD.common index 35315b21f..395e4805d 100644 --- a/windows/PKGBUILD.common +++ b/windows/PKGBUILD.common @@ -12,7 +12,7 @@ build() { cd source wine-msys2-build python setup.py install --prefix=../mingw64 cd .. - rm mingw64/lib/python3.9/site-packages/easy-install.pth + rm -f mingw64/lib/python3.9/site-packages/easy-install.pth } package() { diff --git a/windows/PKGBUILD.pyqtgraph b/windows/PKGBUILD.pyqtgraph new file mode 100644 index 000000000..ab090c3ef --- /dev/null +++ b/windows/PKGBUILD.pyqtgraph @@ -0,0 +1,11 @@ +pkgbase="mingw-w64-python-pyqtgraph" +pkgname="mingw-w64-x86_64-python-pyqtgraph" +pkgrel=1 +pkgdesc="Fast data visualization and GUI tools for scientific / engineering applications" +license=("MIT") +depends=( + "mingw-w64-x86_64-python" + "mingw-w64-x86_64-python-pyqt5" +) + +source PKGBUILD.common diff --git a/windows/default.nix b/windows/default.nix index 68b764fb0..22c708670 100644 --- a/windows/default.nix +++ b/windows/default.nix @@ -28,6 +28,11 @@ let ''; }; in rec { + pyqtgraph-pkg = makeMsys2 { + name = "pyqtgraph"; + src = pkgs.python3Packages.pyqtgraph.src; + inherit (pkgs.python3Packages.pyqtgraph) version; + }; sipyco-pkg = makeMsys2 { name = "sipyco"; src = sipyco; @@ -51,6 +56,7 @@ in rec { '' mkdir $out cd $out + ln -s ${pyqtgraph-pkg}/*.pkg.tar.zst . ln -s ${sipyco-pkg}/*.pkg.tar.zst . ln -s ${artiq-comtools-pkg}/*.pkg.tar.zst . ln -s ${nac3.packages.x86_64-w64-mingw32.nac3artiq-pkg}/*.pkg.tar.zst . From 113a36a9c0ca318c8f04fc707660cc5a4acc3552 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 16:38:04 +0800 Subject: [PATCH 160/352] windows: package qasync --- flake.nix | 1 + windows/PKGBUILD.qasync | 11 +++++++++++ windows/default.nix | 6 ++++++ 3 files changed, 18 insertions(+) create mode 100644 windows/PKGBUILD.qasync diff --git a/flake.nix b/flake.nix index f153e52fe..8c6071975 100644 --- a/flake.nix +++ b/flake.nix @@ -363,6 +363,7 @@ hydraJobs = { inherit (packages.x86_64-linux) artiq artiq-board-kc705-nist_clock openocd-bscanspi; + qasync-msys2-pkg = packages.x86_64-w64-mingw32.qasync-pkg; pyqtgraph-msys2-pkg = packages.x86_64-w64-mingw32.pyqtgraph-pkg; sipyco-msys2-pkg = packages.x86_64-w64-mingw32.sipyco-pkg; artiq-comtools-msys2-pkg = packages.x86_64-w64-mingw32.artiq-comtools-pkg; diff --git a/windows/PKGBUILD.qasync b/windows/PKGBUILD.qasync new file mode 100644 index 000000000..e871cc52f --- /dev/null +++ b/windows/PKGBUILD.qasync @@ -0,0 +1,11 @@ +pkgbase="mingw-w64-python-qasync" +pkgname="mingw-w64-x86_64-python-qasync" +pkgrel=1 +pkgdesc="Implementation of the PEP 3156 Event-Loop with Qt" +license=("BSD") +depends=( + "mingw-w64-x86_64-python" + "mingw-w64-x86_64-python-pyqt5" +) + +source PKGBUILD.common diff --git a/windows/default.nix b/windows/default.nix index 22c708670..8f4a48a1b 100644 --- a/windows/default.nix +++ b/windows/default.nix @@ -28,6 +28,11 @@ let ''; }; in rec { + qasync-pkg = makeMsys2 { + name = "qasync"; + src = artiq.packages.x86_64-linux.qasync.src; + inherit (artiq.packages.x86_64-linux.qasync) version; + }; pyqtgraph-pkg = makeMsys2 { name = "pyqtgraph"; src = pkgs.python3Packages.pyqtgraph.src; @@ -56,6 +61,7 @@ in rec { '' mkdir $out cd $out + ln -s ${qasync-pkg}/*.pkg.tar.zst . ln -s ${pyqtgraph-pkg}/*.pkg.tar.zst . ln -s ${sipyco-pkg}/*.pkg.tar.zst . ln -s ${artiq-comtools-pkg}/*.pkg.tar.zst . From 29c8e3958daf853729dd6b47250393ad3a3944fa Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 17:02:26 +0800 Subject: [PATCH 161/352] windows: depend on qasync --- windows/PKGBUILD.artiq | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/PKGBUILD.artiq b/windows/PKGBUILD.artiq index 28dbd4913..4d3ff9f43 100644 --- a/windows/PKGBUILD.artiq +++ b/windows/PKGBUILD.artiq @@ -7,7 +7,7 @@ depends=( "mingw-w64-x86_64-python" "mingw-w64-x86_64-python-h5py" "mingw-w64-x86_64-python-pyqt5" - # TODO "mingw-w64-x86_64-python-qasync" + "mingw-w64-x86_64-python-qasync" "mingw-w64-x86_64-python-pyqtgraph" "mingw-w64-x86_64-python-numpy" "mingw-w64-x86_64-python-scipy" From ae5c64619ab76ec43010b368092ea48759fc30f5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 17:07:26 +0800 Subject: [PATCH 162/352] windows: work around cretinous setuptools problems --- windows/PKGBUILD.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/PKGBUILD.common b/windows/PKGBUILD.common index 395e4805d..84129304d 100644 --- a/windows/PKGBUILD.common +++ b/windows/PKGBUILD.common @@ -10,7 +10,7 @@ build() { export PYTHONPATH=`pwd`/mingw64/lib/python3.9/site-packages chmod +w -R source cd source - wine-msys2-build python setup.py install --prefix=../mingw64 + wine-msys2-build python setup.py install --single-version-externally-managed --prefix=../mingw64 cd .. rm -f mingw64/lib/python3.9/site-packages/easy-install.pth } From a700c2c4e4d49abdecd89db3a056996f2113c686 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 17:10:57 +0800 Subject: [PATCH 163/352] windows: depend on artiq-comtools --- windows/PKGBUILD.artiq | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/PKGBUILD.artiq b/windows/PKGBUILD.artiq index 4d3ff9f43..0a82f71e0 100644 --- a/windows/PKGBUILD.artiq +++ b/windows/PKGBUILD.artiq @@ -16,6 +16,7 @@ depends=( "mingw-w64-x86_64-python-pygit2" "mingw-w64-x86_64-python-sipyco" "mingw-w64-x86_64-nac3artiq" + "mingw-w64-x86_64-artiq-comtools" ) source PKGBUILD.common From d75f41f8d2a2598d528217b588c57486edd78895 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 17:13:28 +0800 Subject: [PATCH 164/352] windows: work around cretinous setuptools problems (2) --- windows/PKGBUILD.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/PKGBUILD.common b/windows/PKGBUILD.common index 84129304d..b830dc963 100644 --- a/windows/PKGBUILD.common +++ b/windows/PKGBUILD.common @@ -10,7 +10,7 @@ build() { export PYTHONPATH=`pwd`/mingw64/lib/python3.9/site-packages chmod +w -R source cd source - wine-msys2-build python setup.py install --single-version-externally-managed --prefix=../mingw64 + wine-msys2-build python setup.py install --single-version-externally-managed --root=Z:\\`pwd`/../mingw64 cd .. rm -f mingw64/lib/python3.9/site-packages/easy-install.pth } From 13e38913eab515c1a18ab84a8305e20870df5432 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 17:23:52 +0800 Subject: [PATCH 165/352] windows: work around cretinous setuptools problems (3) --- windows/PKGBUILD.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/PKGBUILD.common b/windows/PKGBUILD.common index b830dc963..da3706883 100644 --- a/windows/PKGBUILD.common +++ b/windows/PKGBUILD.common @@ -10,7 +10,7 @@ build() { export PYTHONPATH=`pwd`/mingw64/lib/python3.9/site-packages chmod +w -R source cd source - wine-msys2-build python setup.py install --single-version-externally-managed --root=Z:\\`pwd`/../mingw64 + wine-msys2-build python setup.py install --single-version-externally-managed --prefix=../mingw64 --record=setuptools-sucks.txt cd .. rm -f mingw64/lib/python3.9/site-packages/easy-install.pth } From f704f3daa431cb6b6fb543b44b763ed3ddeb8b48 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 17:35:58 +0800 Subject: [PATCH 166/352] update sipyco --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 132cbbba8..de160fca8 100644 --- a/flake.lock +++ b/flake.lock @@ -92,11 +92,11 @@ ] }, "locked": { - "lastModified": 1649124180, - "narHash": "sha256-NxGYtKeUqvABCkCBixJ1cDJGTPooHh4I2MuWfj0i0Ok=", + "lastModified": 1649151322, + "narHash": "sha256-CwTpGx2Vx/m3bMbeWMculOSsvGmg+OD/hd69dxBwU48=", "owner": "m-labs", "repo": "sipyco", - "rev": "0d61fba000d03692ee5aa66c813977e7db085c31", + "rev": "4a4a04988206db8821c3c8fa33dca478c738677c", "type": "github" }, "original": { From 176490a08352cf6fa9f7f3441081828a3e27db8a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 18:04:49 +0800 Subject: [PATCH 167/352] windows: fix more setuptools problems --- windows/PKGBUILD.common | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/windows/PKGBUILD.common b/windows/PKGBUILD.common index da3706883..e5d8e2a74 100644 --- a/windows/PKGBUILD.common +++ b/windows/PKGBUILD.common @@ -12,7 +12,19 @@ build() { cd source wine-msys2-build python setup.py install --single-version-externally-managed --prefix=../mingw64 --record=setuptools-sucks.txt cd .. + + # setuptools creates this file if it doesn't already exist, which causes conflicts between pacman packages + # see: https://corte.si/posts/code/setuptoolssucks/ rm -f mingw64/lib/python3.9/site-packages/easy-install.pth + # patch broken shebangs (Z:/nix/store/...) + for entrypoint in mingw64/bin/*-script.py; do + [ -f "$entrypoint" ] || continue + sed -i "1s|#!.*|#!python|" $entrypoint + done + for entrypoint in mingw64/bin/*-script.pyw; do + [ -f "$entrypoint" ] || continue + sed -i "1s|#!.*|#!pythonw|" $entrypoint + done } package() { From 9b910679f8546c22ad052e61956dbaf90f53cb7e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Apr 2022 18:22:59 +0800 Subject: [PATCH 168/352] doc: MSYS2 --- CONTRIBUTING.rst | 2 +- README.rst | 2 +- doc/manual/installing.rst | 78 +++++++++++------------------------- doc/manual/introduction.rst | 2 +- doc/manual/list_of_ndsps.rst | 50 +++++++++++------------ 5 files changed, 52 insertions(+), 82 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 88100ddf5..3780dba43 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -26,7 +26,7 @@ report if possible: * Operating System * ARTIQ version (with recent versions of ARTIQ, run ``artiq_client --version``) * Version of the gateware and runtime loaded in the core device (in the output of ``artiq_coremgmt -D .... log``) - * If using Conda, output of `conda list` + * If using MSYS2, output of `pacman -Q` * Hardware involved diff --git a/README.rst b/README.rst index 216c77ba1..cef2fb286 100644 --- a/README.rst +++ b/README.rst @@ -13,7 +13,7 @@ ARTIQ uses FPGA hardware to perform its time-critical tasks. The `Sinara hardwar ARTIQ is designed to be portable to hardware platforms from different vendors and FPGA manufacturers. Several different configurations of a `FPGA evaluation kit `_ and of a `Zynq evaluation kit `_ are also used and supported. FPGA platforms can be combined with any number of additional peripherals, either already accessible from ARTIQ or made accessible with little effort. -ARTIQ and its dependencies are available in the form of Nix packages (for Linux) and Conda packages (for Windows and Linux). See `the manual `_ for installation instructions. +ARTIQ and its dependencies are available in the form of Nix packages (for Linux) and MSYS2 packages (for Windows). See `the manual `_ for installation instructions. Packages containing pre-compiled binary images to be loaded onto the hardware platforms are supplied for each configuration. Like any open source software ARTIQ can equally be built and installed directly from `source `_. diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 3bc38cd41..3821fefd8 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -1,13 +1,7 @@ Installing ARTIQ ================ -ARTIQ can be installed using the Nix (on Linux) or Conda (on Windows or Linux) package managers. - -Nix is an innovative, robust, fast, and high-quality solution that comes with a larger collection of packages and features than Conda. However, Windows support is poor (using it with Windows Subsystem for Linux still has many problems) and Nix can be harder to learn. - -Conda has a more traditional approach to package management, is much more limited, slow, and lower-quality than Nix, but it supports Windows and it is simpler to use when it functions correctly. - -In the current state of affairs, we recommend that Linux users install ARTIQ via Nix and Windows users install it via Conda. +ARTIQ can be installed using the Nix package manager on Linux, and using the MSYS2 software distribution on Windows. .. _installing-nix-users: @@ -90,39 +84,24 @@ You can create directories containing each a ``flake.nix`` that correspond to di If your favorite package is not available with Nix, contact us using the helpdesk@ email. -Installing via Conda (Windows, Linux) -------------------------------------- +Installing with MSYS2 (Windows) +------------------------------- -.. warning:: - For Linux users, the Nix package manager is preferred, as it is more reliable and faster than Conda. +Install `MSYS2 `, and open "MSYS2 MinGW x64". Edit ``/etc/pacman.conf`` to add: +``` +[artiq] +SigLevel = Optional TrustAll +Server = https://lab.m-labs.hk/msys2 +``` -First, install `Anaconda `_ or the more minimalistic `Miniconda `_. - -After installing either Anaconda or Miniconda, open a new terminal (also known as command line, console, or shell and denoted here as lines starting with ``$``) and verify the following command works:: - - $ conda - -Executing just ``conda`` should print the help of the ``conda`` command. If your shell does not find the ``conda`` command, make sure that the Conda binaries are in your ``$PATH``. If ``$ echo $PATH`` does not show the Conda directories, add them: execute ``$ export PATH=$HOME/miniconda3/bin:$PATH`` if you installed Conda into ``~/miniconda3``. - -Controllers for third-party devices (e.g. Thorlabs TCube, Lab Brick Digital Attenuator, etc.) that are not shipped with ARTIQ can also be installed with this script. Browse `Hydra `_ or see the list of NDSPs in this manual to find the names of the corresponding packages, and list them at the beginning of the script. - -Set up the Conda channel and install ARTIQ into a new Conda environment: :: - - $ conda config --prepend channels https://conda.m-labs.hk/artiq-beta - $ conda config --append channels conda-forge - $ conda create -n artiq artiq +Then run the following commands: +``` +pacman -Syu +pacman -S mingw-w64-x86_64-artiq +``` .. note:: - If you do not need to flash boards, the ``artiq`` package is sufficient. The packages named ``artiq-board-*`` contain only firmware for the FPGA board, and you should not install them unless you are reflashing an FPGA board. Controllers for third-party devices (e.g. Thorlabs TCube, Lab Brick Digital Attenuator, etc.) that are not shipped with ARTIQ can also be installed with Conda. Browse `Hydra `_ or see the list of NDSPs in this manual to find the names of the corresponding packages. - -After the installation, activate the newly created environment by name. :: - - $ conda activate artiq - -This activation has to be performed in every new shell you open to make the ARTIQ tools from that environment available. - -.. note:: - Some ARTIQ examples also require matplotlib and numba, and they must be installed manually for running those examples. They are available in Conda. + Some ARTIQ examples also require matplotlib and numba, and they must be installed manually for running those examples. They are available in MSYS2. Upgrading ARTIQ (with Nix) -------------------------- @@ -133,22 +112,15 @@ To rollback to the previous version, respectively use ``$ nix profile rollback`` You may need to reflash the gateware and firmware of the core device to keep it synchronized with the software. -Upgrading ARTIQ (with Conda) +Upgrading ARTIQ (with MSYS2) ---------------------------- -When upgrading ARTIQ or when testing different versions it is recommended that new Conda environments are created instead of upgrading the packages in existing environments. -Keep previous environments around until you are certain that they are not needed anymore and a new environment is known to work correctly. +Run this command to update the entire MSYS2 environment including ARTIQ: :: -To install the latest version, just select a different environment name and run the installation command again. - -Switching between Conda environments using commands such as ``$ conda deactivate artiq-6`` and ``$ conda activate artiq-5`` is the recommended way to roll back to previous versions of ARTIQ. + $ pacman -Syu You may need to reflash the gateware and firmware of the core device to keep it synchronized with the software. -You can list the environments you have created using:: - - $ conda env list - Flashing gateware and firmware into the core device --------------------------------------------------- @@ -169,11 +141,14 @@ Installing OpenOCD OpenOCD can be used to write the binary images into the core device FPGA board's flash memory. -With Nix, add ``aqmain.openocd-bscanspi`` to the shell packages. Be careful not to add ``pkgs.openocd`` instead - this would install OpenOCD from the NixOS package collection, which does not support ARTIQ boards. +With Nix, add ``aqmain.openocd-bscanspi`` to the shell packages. +Be careful not to add ``pkgs.openocd`` instead - this would install OpenOCD from the NixOS package collection, which does not contain the bscanspi bitstreams necessary to flash ARTIQ boards. -With Conda, install ``openocd`` as follows:: +With MSYS2, install ``openocd`` as follows:: - $ conda install -c m-labs openocd + $ pacman -S mingw-w64-x86_64-openocd + +and manually copy the bscanspi bitstreams where OpenOCD will find them. .. _configuring-openocd: @@ -196,11 +171,6 @@ If you installed OpenOCD on Linux using Nix, use the ``which`` command to determ NixOS users should of course configure OpenOCD through ``/etc/nixos/configuration.nix`` instead. -If you installed OpenOCD on Linux using Conda and are using the Conda environment ``artiq``, then execute the statements below. If you are using a different environment, you will have to replace ``artiq`` with the name of your environment:: - - $ sudo cp ~/.conda/envs/artiq/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d - $ sudo udevadm trigger - On Windows, a third-party tool, `Zadig `_, is necessary. Use it as follows: 1. Make sure the FPGA board's JTAG USB port is connected to your computer. diff --git a/doc/manual/introduction.rst b/doc/manual/introduction.rst index 23eaa98a9..d43453088 100644 --- a/doc/manual/introduction.rst +++ b/doc/manual/introduction.rst @@ -14,7 +14,7 @@ ARTIQ uses FPGA hardware to perform its time-critical tasks. The `Sinara hardwar ARTIQ is designed to be portable to hardware platforms from different vendors and FPGA manufacturers. Several different configurations of a `high-end FPGA evaluation kit `_ are also used and supported. FPGA platforms can be combined with any number of additional peripherals, either already accessible from ARTIQ or made accessible with little effort. -ARTIQ and its dependencies are available in the form of Nix packages (for Linux) and Conda packages (for Windows and Linux). +ARTIQ and its dependencies are available in the form of Nix packages (for Linux) and MSYS2 packages (for Windows). Packages containing pre-compiled binary images to be loaded onto the hardware platforms are supplied for each configuration. Like any open source software ARTIQ can equally be built and installed directly from `source `_. diff --git a/doc/manual/list_of_ndsps.rst b/doc/manual/list_of_ndsps.rst index 12d698e20..03ba08a9c 100644 --- a/doc/manual/list_of_ndsps.rst +++ b/doc/manual/list_of_ndsps.rst @@ -3,28 +3,28 @@ List of available NDSPs The following network device support packages are available for ARTIQ. If you would like to add yours to this list, just send us an email or a pull request. -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ -| Equipment | Nix package | Conda package | Documentation | URL | -+=================================+===================================+==================================+=====================================================================================================+========================================================+ -| PDQ2 | Not available | Not available | `HTML `_ | https://github.com/m-labs/pdq | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ -| Lab Brick Digital Attenuator | ``lda`` | ``lda`` | `HTML `_ | https://github.com/m-labs/lda | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ -| Novatech 409B | ``novatech409b`` | ``novatech409b`` | `HTML `_ | https://github.com/m-labs/novatech409b | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ -| Thorlabs T-Cubes | ``thorlabs_tcube`` | ``thorlabs_tcube`` | `HTML `_ | https://github.com/m-labs/thorlabs_tcube | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ -| Korad KA3005P | ``korad_ka3005p`` | ``korad_ka3005p`` | `HTML `_ | https://github.com/m-labs/korad_ka3005p | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ -| Newfocus 8742 | ``newfocus8742`` | ``newfocus8742`` | `HTML `_ | https://github.com/quartiq/newfocus8742 | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ -| Princeton Instruments PICam | Not available | Not available | Not available | https://github.com/quartiq/picam | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ -| Anel HUT2 power distribution | ``hut2`` | ``hut2`` | `HTML `_ | https://github.com/quartiq/hut2 | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ -| TOPTICA lasers | ``toptica-lasersdk-artiq`` | ``toptica-lasersdk-artiq`` | Not available | https://github.com/quartiq/lasersdk-artiq | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ -| HighFinesse wavemeters | ``highfinesse-net`` | ``highfinesse-net`` | `HTML `_ | https://github.com/quartiq/highfinesse-net | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ -| InfluxDB database | Not available | Not available | `HTML `_ | https://gitlab.com/charlesbaynham/artiq_influx_generic | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------+ ++---------------------------------+--------------------------------------------------------+ +| Equipment | URL | ++=================================+========================================================+ +| PDQ2 | https://github.com/m-labs/pdq | ++---------------------------------+--------------------------------------------------------+ +| Lab Brick Digital Attenuator | https://github.com/m-labs/lda | ++---------------------------------+--------------------------------------------------------+ +| Novatech 409B | https://github.com/m-labs/novatech409b | ++---------------------------------+--------------------------------------------------------+ +| Thorlabs T-Cubes | https://github.com/m-labs/thorlabs_tcube | ++---------------------------------+--------------------------------------------------------+ +| Korad KA3005P | https://github.com/m-labs/korad_ka3005p | ++---------------------------------+--------------------------------------------------------+ +| Newfocus 8742 | https://github.com/quartiq/newfocus8742 | ++---------------------------------+--------------------------------------------------------+ +| Princeton Instruments PICam | https://github.com/quartiq/picam | ++---------------------------------+--------------------------------------------------------+ +| Anel HUT2 power distribution | https://github.com/quartiq/hut2 | ++---------------------------------+--------------------------------------------------------+ +| TOPTICA lasers | https://github.com/quartiq/lasersdk-artiq | ++---------------------------------+--------------------------------------------------------+ +| HighFinesse wavemeters | https://github.com/quartiq/highfinesse-net | ++---------------------------------+--------------------------------------------------------+ +| InfluxDB database | https://gitlab.com/charlesbaynham/artiq_influx_generic | ++---------------------------------+--------------------------------------------------------+ From dc00f811e254c4518d856cc31a52f9fa4ecabc6a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 10 Apr 2022 08:34:54 +0800 Subject: [PATCH 169/352] flake: update dependencies --- flake.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/flake.lock b/flake.lock index de160fca8..25f48751e 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1649124608, - "narHash": "sha256-ZBmCeuOSZTxa9c9nbdFtSCDy940HlMAhNNh5TA42f1E=", + "lastModified": 1649525326, + "narHash": "sha256-kg5rcnlKVPhmDCFRB5uh+pzLQtIeZfR6+/kjVZuTXSg=", "ref": "master", - "rev": "e05b0bf5dc427952a60b0dbe696de2ea239d9206", - "revCount": 724, + "rev": "f66f66b3a4bd6e84d176c61e250dd71ea602a26b", + "revCount": 733, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -124,11 +124,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1641889368, - "narHash": "sha256-0Ai25lry9ju1HxFmfMRNKG8mamBqvw+kvDfpuK8Dtjo=", + "lastModified": 1649324486, + "narHash": "sha256-Mw/fQS3lHFvCm7L1k63joRkz5uyijQfywcOq+X2+o2s=", "ref": "master", - "rev": "7242dc5a41732135425acc4871487461dfae6c66", - "revCount": 2419, + "rev": "f1dc58d2b8c222ba41c25cee4301626625f46e43", + "revCount": 2420, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From 5041e5f6bda041a59c7dd8c548b1b4e0650d95ef Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Apr 2022 09:15:48 +0800 Subject: [PATCH 170/352] flake: update dependencies --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 25f48751e..b99daec18 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1649525326, - "narHash": "sha256-kg5rcnlKVPhmDCFRB5uh+pzLQtIeZfR6+/kjVZuTXSg=", + "lastModified": 1649725984, + "narHash": "sha256-A5n116AtjrWaiWlx0fjGEJ93BaEXkjaSWBntK+TEA14=", "ref": "master", - "rev": "f66f66b3a4bd6e84d176c61e250dd71ea602a26b", - "revCount": 733, + "rev": "93e9a6a38a179770ce12b38cb8e54347b06cc115", + "revCount": 736, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,11 +60,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1649024309, - "narHash": "sha256-AWbvj/NHZXVwAnHaVOFlxg7tcNerEKrKBmgGfztSHWM=", + "lastModified": 1649619156, + "narHash": "sha256-p0q4zpuKMwrzGF+5ZU7Thnpac5TinhDI9jr2mBxhV4w=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "af0a9bc0e5341855518e9c1734d7ef913e5138b9", + "rev": "e7d63bd0d50df412f5a1d8acfa3caae75522e347", "type": "github" }, "original": { @@ -92,11 +92,11 @@ ] }, "locked": { - "lastModified": 1649151322, - "narHash": "sha256-CwTpGx2Vx/m3bMbeWMculOSsvGmg+OD/hd69dxBwU48=", + "lastModified": 1649724535, + "narHash": "sha256-15Nun4EY35j+6SPZkjzZtyH/ncxLS60KuGJjFh5kSTc=", "owner": "m-labs", "repo": "sipyco", - "rev": "4a4a04988206db8821c3c8fa33dca478c738677c", + "rev": "939f84f9b5eef7efbf7423c735d1834783b6140e", "type": "github" }, "original": { From c171deec51aa104e4e806e616b171395fee5ef97 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Apr 2022 15:58:54 +0800 Subject: [PATCH 171/352] sim: improve formatting --- artiq/sim/devices.py | 2 +- artiq/sim/time.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/sim/devices.py b/artiq/sim/devices.py index 3e2295bf6..18b997b69 100644 --- a/artiq/sim/devices.py +++ b/artiq/sim/devices.py @@ -93,7 +93,7 @@ class WaveOutput: @kernel def pulse(self, frequency, duration): - time.manager.event(("pulse", self.name, frequency, duration)) + time.manager.event(("pulse", self.name, frequency, self.core.seconds_to_mu(duration))) delay(duration) diff --git a/artiq/sim/time.py b/artiq/sim/time.py index 676966735..7fa93d891 100644 --- a/artiq/sim/time.py +++ b/artiq/sim/time.py @@ -62,7 +62,7 @@ class Manager: r = "" prev_time = 0*s for time, description in sorted(self.timeline, key=itemgetter(0)): - r += "@{:.9f} (+{:.9f}) ".format(time, time-prev_time) + r += "{:35}".format("@{:.9f} (+{:.9f}) ".format(time, time-prev_time)) for item in description: r += "{:16}".format(str(item)) r += "\n" From 83676927b58e3a1dadff48b04a6497f44eefe7ad Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Apr 2022 15:59:20 +0800 Subject: [PATCH 172/352] examples/simple_simulation: fix --- artiq/examples/no_hardware/repository/simple_simulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/no_hardware/repository/simple_simulation.py b/artiq/examples/no_hardware/repository/simple_simulation.py index 1b9205825..e07c6f770 100644 --- a/artiq/examples/no_hardware/repository/simple_simulation.py +++ b/artiq/examples/no_hardware/repository/simple_simulation.py @@ -27,7 +27,7 @@ def main(): dmgr["core"] = devices.Core(dmgr) for wo in "abcd": dmgr[wo] = devices.WaveOutput(dmgr, wo) - exp = SimpleSimulation(dmgr) + exp = SimpleSimulation((dmgr, None, None, {})) exp.run() if __name__ == "__main__": From 125572b5531209146ef60259f0e789a6775155c5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Apr 2022 16:01:39 +0800 Subject: [PATCH 173/352] language: reimplement sim --- artiq/language/core.py | 83 ++++++++++++++++++++++++++++++++++++++---- artiq/sim/time.py | 2 +- 2 files changed, 76 insertions(+), 9 deletions(-) diff --git a/artiq/language/core.py b/artiq/language/core.py index 0e66cdb54..e1dc7f0ec 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -17,7 +17,9 @@ __all__ = [ "extern", "kernel", "portable", "nac3", "rpc", "print_rpc", "Option", "Some", "none", "UnwrapNoneError", + "set_time_manager", "parallel", "sequential", + "delay_mu", "now_mu", "at_mu", "set_watchdog_factory", "watchdog", "TerminationRequested", ] @@ -154,19 +156,84 @@ def Some(v: T) -> Option[T]: none = Option(None) +class _DummyTimeManager: + def _not_implemented(self, *args, **kwargs): + raise NotImplementedError( + "Attempted to interpret kernel without a time manager") + + enter_sequential = _not_implemented + enter_parallel = _not_implemented + exit = _not_implemented + take_time_mu = _not_implemented + get_time_mu = _not_implemented + set_time_mu = _not_implemented + take_time = _not_implemented + +_time_manager = _DummyTimeManager() + +def set_time_manager(time_manager): + """Set the time manager used for simulating kernels by running them + directly inside the Python interpreter. The time manager responds to the + entering and leaving of interleave/parallel/sequential blocks, delays, etc. and + provides a time-stamped logging facility for events. + """ + global _time_manager + _time_manager = time_manager + + @nac3 -class KernelContextManager: - @kernel +class _ParallelContextManager: + """In a parallel block, all statements start their execution at + the same time. + The execution time of a parallel block is the execution time of its longest + statement. A parallel block may contain sequential blocks, which themselves + may contain parallel blocks, etc. + """ + # Those methods are not actual RPCs, but they need to be registered with + # NAC3 for the context manager to typecheck. + # In the codegen phase, NAC3ARTIQ detects those special context managers + # and takes over, without generating the RPC calling code. + @rpc def __enter__(self): - pass + _time_manager.enter_parallel() - @kernel - def __exit__(self): - pass + @rpc + def __exit__(self, *exc_info): + _time_manager.exit() -parallel = KernelContextManager() -sequential = KernelContextManager() +@nac3 +class _SequentialContextManager: + """In a sequential block, statements are executed one after another, with + the time increasing as one moves down the statement list.""" + @rpc + def __enter__(self): + _time_manager.enter_sequential() + @rpc + def __exit__(self, *exc_info): + _time_manager.exit() + +parallel = _ParallelContextManager() +sequential = _SequentialContextManager() + + +def delay_mu(duration): + """Increases the RTIO time by the given amount (in machine units).""" + _time_manager.take_time_mu(duration) + + +def now_mu(): + """Retrieve the current RTIO timeline cursor, in machine units. + Note the conceptual difference between this and the current value of the + hardware RTIO counter; see e.g. + :meth:`artiq.coredevice.core.Core.get_rtio_counter_mu` for the latter. + """ + return _time_manager.get_time_mu() + + +def at_mu(time): + """Sets the RTIO time to the specified absolute value, in machine units.""" + _time_manager.set_time_mu(time) class _DummyWatchdog: diff --git a/artiq/sim/time.py b/artiq/sim/time.py index 7fa93d891..d090962eb 100644 --- a/artiq/sim/time.py +++ b/artiq/sim/time.py @@ -70,4 +70,4 @@ class Manager: return r manager = Manager() -# NAC3TODO core_language.set_time_manager(manager) +core_language.set_time_manager(manager) From 89aa3a3d9de50a2abd0985cc8e6d2ab501eb6f6c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Apr 2022 16:01:56 +0800 Subject: [PATCH 174/352] sim/devices: port to NAC3 --- artiq/sim/devices.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/artiq/sim/devices.py b/artiq/sim/devices.py index 18b997b69..fc258ed48 100644 --- a/artiq/sim/devices.py +++ b/artiq/sim/devices.py @@ -1,18 +1,18 @@ from random import Random -import numpy -from artiq.language.core import kernel +from artiq.language.core import kernel, sequential, delay_mu from artiq.sim import time class Core: def __init__(self, dmgr): - self.ref_period = 1 + self.ref_period = 1e-6 self._level = 0 def run(self, k_function, k_args, k_kwargs): self._level += 1 - r = k_function.artiq_embedded.function(*k_args, **k_kwargs) + with sequential: + r = getattr(k_function.__self__, k_function.__name__).__wrapped__(k_function.__self__, *k_args, **k_kwargs) self._level -= 1 if self._level == 0: print(time.manager.format_timeline()) @@ -20,33 +20,35 @@ class Core: return r def seconds_to_mu(self, seconds): - return numpy.int64(seconds//self.ref_period) + return round(seconds/self.ref_period) def mu_to_seconds(self, mu): return mu*self.ref_period + def delay(self, seconds): + delay_mu(self.seconds_to_mu(seconds)) + class Input: def __init__(self, dmgr, name): self.core = dmgr.get("core") self.name = name - self.prng = Random() @kernel def gate_rising(self, duration): time.manager.event(("gate_rising", self.name, duration)) - delay(duration) + self.core.delay(duration) @kernel def gate_falling(self, duration): time.manager.event(("gate_falling", self.name, duration)) - delay(duration) + self.core.delay(duration) @kernel def gate_both(self, duration): time.manager.event(("gate_both", self.name, duration)) - delay(duration) + self.core.delay(duration) @kernel def count(self, up_to_timestamp_mu): @@ -75,7 +77,7 @@ class Output: @kernel def pulse(self, duration): time.manager.event(("pulse", self.name, duration)) - delay(duration) + self.core.delay(duration) @kernel def on(self): @@ -94,7 +96,7 @@ class WaveOutput: @kernel def pulse(self, frequency, duration): time.manager.event(("pulse", self.name, frequency, self.core.seconds_to_mu(duration))) - delay(duration) + self.core.delay(duration) class VoltageOutput: From dd57fdc530baf926a5f354dc1c2bd90564affd96 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 18 Apr 2022 18:53:31 +0800 Subject: [PATCH 175/352] flake: update NAC3 --- artiq/examples/kc705_nist_clock/device_db.py | 2 +- flake.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index 1930f584b..e95939206 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -1,7 +1,7 @@ # This is an example device database that needs to be adapted to your setup. # The list of devices here is not exhaustive. -core_addr = "192.168.1.50" +core_addr = "localhost" device_db = { # Core device diff --git a/flake.lock b/flake.lock index b99daec18..7b4c21a7b 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1649725984, - "narHash": "sha256-A5n116AtjrWaiWlx0fjGEJ93BaEXkjaSWBntK+TEA14=", + "lastModified": 1650278885, + "narHash": "sha256-+yRsiO0h9sLvCaAao5Qp0XRrCIbgvGdPpnK4E3Iiu4s=", "ref": "master", - "rev": "93e9a6a38a179770ce12b38cb8e54347b06cc115", - "revCount": 736, + "rev": "05be5e93c46a480ecade167171acb42f91f88eb9", + "revCount": 753, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,11 +60,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1649619156, - "narHash": "sha256-p0q4zpuKMwrzGF+5ZU7Thnpac5TinhDI9jr2mBxhV4w=", + "lastModified": 1650244918, + "narHash": "sha256-DsS5nxjTpnoUC4pNXJI1rit7TnDTij8vQDa5PtcDCD0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e7d63bd0d50df412f5a1d8acfa3caae75522e347", + "rev": "7b38b03d76ab71bdc8dc325e3f6338d984cc35ca", "type": "github" }, "original": { From efea248b692d9b24d64114ea04ff071363c2202a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Apr 2022 00:04:21 +0800 Subject: [PATCH 176/352] flake: use NAC3 PGO build --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 8c6071975..244bbb491 100644 --- a/flake.nix +++ b/flake.nix @@ -85,7 +85,7 @@ nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; # keep llvm_x and lld_x in sync with nac3 - propagatedBuildInputs = [ pkgs.llvm_13 pkgs.lld_13 nac3.packages.x86_64-linux.nac3artiq sipyco.packages.x86_64-linux.sipyco artiq-comtools.packages.x86_64-linux.artiq-comtools ] + propagatedBuildInputs = [ pkgs.llvm_13 pkgs.lld_13 nac3.packages.x86_64-linux.nac3artiq-pgo sipyco.packages.x86_64-linux.sipyco artiq-comtools.packages.x86_64-linux.artiq-comtools ] ++ (with pkgs.python3Packages; [ pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial h5py pyqt5 qasync ]); dontWrapQtApps = true; From 09f8f9f8bfdcdc407661372fa75b47dda3e3ba95 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Apr 2022 00:04:33 +0800 Subject: [PATCH 177/352] flake: update NAC3 --- flake.lock | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 7b4c21a7b..9100ac0e2 100644 --- a/flake.lock +++ b/flake.lock @@ -42,14 +42,15 @@ }, "nac3": { "inputs": { - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "sipyco": "sipyco" }, "locked": { - "lastModified": 1650278885, - "narHash": "sha256-+yRsiO0h9sLvCaAao5Qp0XRrCIbgvGdPpnK4E3Iiu4s=", + "lastModified": 1650297523, + "narHash": "sha256-B61t3/L8rzyxl4AkaF3OrjnWKAWWwB06ZkmnD8hiScM=", "ref": "master", - "rev": "05be5e93c46a480ecade167171acb42f91f88eb9", - "revCount": 753, + "rev": "42d1aad50734b70d7f05f8cfd89696facb4bf20f", + "revCount": 755, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,7 +80,7 @@ "artiq-comtools": "artiq-comtools", "mozilla-overlay": "mozilla-overlay", "nac3": "nac3", - "sipyco": "sipyco", + "sipyco": "sipyco_2", "src-migen": "src-migen", "src-misoc": "src-misoc" } @@ -105,6 +106,27 @@ "type": "github" } }, + "sipyco_2": { + "inputs": { + "nixpkgs": [ + "nac3", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1649724535, + "narHash": "sha256-15Nun4EY35j+6SPZkjzZtyH/ncxLS60KuGJjFh5kSTc=", + "owner": "m-labs", + "repo": "sipyco", + "rev": "939f84f9b5eef7efbf7423c735d1834783b6140e", + "type": "github" + }, + "original": { + "owner": "m-labs", + "repo": "sipyco", + "type": "github" + } + }, "src-migen": { "flake": false, "locked": { From 4e7b1c76cc89f021c752871bd9cabe814f1c4a2b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Apr 2022 00:10:39 +0800 Subject: [PATCH 178/352] flake: nix2.5 metadata --- flake.lock | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 9100ac0e2..3916a2404 100644 --- a/flake.lock +++ b/flake.lock @@ -75,6 +75,22 @@ "type": "github" } }, + "nixpkgs_2": { + "locked": { + "lastModified": 1650244918, + "narHash": "sha256-DsS5nxjTpnoUC4pNXJI1rit7TnDTij8vQDa5PtcDCD0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "7b38b03d76ab71bdc8dc325e3f6338d984cc35ca", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-21.11", + "repo": "nixpkgs", + "type": "github" + } + }, "root": { "inputs": { "artiq-comtools": "artiq-comtools", @@ -87,10 +103,7 @@ }, "sipyco": { "inputs": { - "nixpkgs": [ - "nac3", - "nixpkgs" - ] + "nixpkgs": "nixpkgs_2" }, "locked": { "lastModified": 1649724535, From 86142db56b6ed4b6df101ffe368c00e22b91356a Mon Sep 17 00:00:00 2001 From: mwojcik Date: Fri, 22 Apr 2022 11:03:57 +0800 Subject: [PATCH 179/352] artiq_sinara_tester: fix urukul rf switch --- artiq/frontend/artiq_sinara_tester.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index 73de43a45..809fcb521 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -333,13 +333,13 @@ class SinaraTester(EnvExperiment): print("Press ENTER when done.") input() - sw = [channel_dev for channel_name, channel_dev in self.urukuls if hasattr(channel_dev, "sw")] + sw = [channel_dev for channel_name, channel_dev in self.urukuls if channel_dev.sw.is_some()] if sw: print("Testing RF switch control. Check LEDs at urukul RF ports.") print("Press ENTER when done.") for swi in sw: self.cfg_sw_off_urukul(swi) - self.rf_switch_wave([swi.sw for swi in sw]) + self.rf_switch_wave([swi.sw.unwrap() for swi in sw]) @kernel def init_mirny(self, cpld: Mirny): From 8c825505fdc5045bb26b012eb0eb6fdbc0638da2 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Tue, 26 Apr 2022 12:52:58 +0800 Subject: [PATCH 180/352] artiq_sinara_tester: fix mirny/almazny freq type --- artiq/frontend/artiq_sinara_tester.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index 809fcb521..dd16a5934 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -408,7 +408,7 @@ class SinaraTester(EnvExperiment): print("Testing attenuators. Frequencies:") for card_n, channels in enumerate(chunker(self.mirnies, 4)): for channel_n, (channel_name, channel_dev) in enumerate(channels): - frequency = 2000 + card_n * 250 + channel_n * 50 + frequency = 2000. + card_n * 250 + channel_n * 50 print("{}\t{}MHz".format(channel_name, frequency*2)) self.setup_mirny(channel_dev, frequency) print("{} info: {}".format(channel_name, channel_dev.info())) @@ -450,7 +450,7 @@ class SinaraTester(EnvExperiment): print("Frequencies:") for card_n, channels in enumerate(chunker(self.mirnies, 4)): for channel_n, (channel_name, channel_dev) in enumerate(channels): - frequency = 1000*(card_n + 1) + channel_n * 100 + frequency = 1000.*(card_n + 1) + channel_n * 100 print("{}\t{}MHz".format(channel_name, frequency)) self.setup_mirny(channel_dev, frequency) print("{} info: {}".format(channel_name, channel_dev.info())) From 4c21d4a19c45ce942a55b4806f82f65e5ea5719b Mon Sep 17 00:00:00 2001 From: mwojcik Date: Wed, 27 Apr 2022 11:57:20 +0800 Subject: [PATCH 181/352] artiq_sinara_tester: fix almazny attenuation type --- artiq/coredevice/mirny.py | 1 - artiq/frontend/artiq_sinara_tester.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py index 95247e6d2..44f08f1dc 100644 --- a/artiq/coredevice/mirny.py +++ b/artiq/coredevice/mirny.py @@ -193,7 +193,6 @@ class Almazny: :param host_mirny - Mirny device Almazny is connected to """ - core: KernelInvariant[Core] mirny_cpld: KernelInvariant[Mirny] att_mu: Kernel[list[int32]] channel_sw: Kernel[list[int32]] diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index dd16a5934..209b52e0d 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -423,7 +423,7 @@ class SinaraTester(EnvExperiment): input() print("RF ON, all attenuators OFF. Press ENTER when done.") for i in range(4): - self.almazny_set_attenuators(almazny, i, 0) + self.almazny_set_attenuators(almazny, i, 0.) input() print("SR outputs are OFF. Press ENTER when done.") self.almazny_toggle_output(almazny, False) From 72aec819f78f0eb064f2a89eb5dd7372c7709b77 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Apr 2022 13:46:44 +0800 Subject: [PATCH 182/352] revert incorrectly committed part of dd57fdc530ba --- artiq/examples/kc705_nist_clock/device_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index e95939206..1930f584b 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -1,7 +1,7 @@ # This is an example device database that needs to be adapted to your setup. # The list of devices here is not exhaustive. -core_addr = "localhost" +core_addr = "192.168.1.50" device_db = { # Core device From 614dfde33d5dbd4273f6c6655f2c0e95cd52f9bf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Apr 2022 15:43:16 +0800 Subject: [PATCH 183/352] flake: update dependencies --- flake.lock | 65 +++++++++++++----------------------------------------- 1 file changed, 15 insertions(+), 50 deletions(-) diff --git a/flake.lock b/flake.lock index 3916a2404..4315f26f3 100644 --- a/flake.lock +++ b/flake.lock @@ -27,11 +27,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1645464064, - "narHash": "sha256-YeN4bpPvHkVOpQzb8APTAfE7/R+MFMwJUMkqmfvytSk=", + "lastModified": 1650459918, + "narHash": "sha256-sroCK+QJTmoXtcRkwZyKOP9iAYOPID2Bwdxn4GkG16w=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "15b7a05f20aab51c4ffbefddb1b448e862dccb7d", + "rev": "e1f7540fc0a8b989fb8cf701dc4fd7fc76bcf168", "type": "github" }, "original": { @@ -42,15 +42,14 @@ }, "nac3": { "inputs": { - "nixpkgs": "nixpkgs", - "sipyco": "sipyco" + "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1650297523, - "narHash": "sha256-B61t3/L8rzyxl4AkaF3OrjnWKAWWwB06ZkmnD8hiScM=", + "lastModified": 1651045306, + "narHash": "sha256-YNrfAwepqN4Fv5tTLzuZeKEEFvY1uL25IC2wQAQPf40=", "ref": "master", - "rev": "42d1aad50734b70d7f05f8cfd89696facb4bf20f", - "revCount": 755, + "rev": "3f327113b25ce34519fe686bd5531ef0efa31e27", + "revCount": 763, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -61,27 +60,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1650244918, - "narHash": "sha256-DsS5nxjTpnoUC4pNXJI1rit7TnDTij8vQDa5PtcDCD0=", + "lastModified": 1650921206, + "narHash": "sha256-RGlfTC2ktqLVw0gBvZeCM//B4ig2CdQJm39sDvm0DBQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7b38b03d76ab71bdc8dc325e3f6338d984cc35ca", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-21.11", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1650244918, - "narHash": "sha256-DsS5nxjTpnoUC4pNXJI1rit7TnDTij8vQDa5PtcDCD0=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "7b38b03d76ab71bdc8dc325e3f6338d984cc35ca", + "rev": "3a9e0f239d80fa134e8fcbdee4dfc793902da37e", "type": "github" }, "original": { @@ -96,30 +79,12 @@ "artiq-comtools": "artiq-comtools", "mozilla-overlay": "mozilla-overlay", "nac3": "nac3", - "sipyco": "sipyco_2", + "sipyco": "sipyco", "src-migen": "src-migen", "src-misoc": "src-misoc" } }, "sipyco": { - "inputs": { - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1649724535, - "narHash": "sha256-15Nun4EY35j+6SPZkjzZtyH/ncxLS60KuGJjFh5kSTc=", - "owner": "m-labs", - "repo": "sipyco", - "rev": "939f84f9b5eef7efbf7423c735d1834783b6140e", - "type": "github" - }, - "original": { - "owner": "m-labs", - "repo": "sipyco", - "type": "github" - } - }, - "sipyco_2": { "inputs": { "nixpkgs": [ "nac3", @@ -143,11 +108,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1639659493, - "narHash": "sha256-qpVj/yJf4hDDc99XXpVPH4EbLC8aCmEtACn5qNc3DGI=", + "lastModified": 1650337393, + "narHash": "sha256-rm1SlFmF2ASz0vIy2nDEzGlyRw2oYNeJRr8Kh8Mg2Qc=", "owner": "m-labs", "repo": "migen", - "rev": "ac703010eaa06ac9b6e32f97c6fa98b15de22b31", + "rev": "d4e3f34177c32f09904397179e6ed9c83175e528", "type": "github" }, "original": { From d6f1c5984a5542ad8a1483a10e271a16dfcd0859 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Wed, 27 Apr 2022 17:31:19 +0800 Subject: [PATCH 184/352] artiq_sinara_tester: fix urukul eeprom_word type --- artiq/frontend/artiq_sinara_tester.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index 209b52e0d..78361a380 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -318,7 +318,7 @@ class SinaraTester(EnvExperiment): offset = channel_dev.sync_data.eeprom_offset sync_delay_seed, io_update_delay = self.calibrate_urukul(channel_dev) print("{}\t{} {}".format(channel_name, sync_delay_seed, io_update_delay)) - eeprom_word = (sync_delay_seed << 24) | (io_update_delay << 16) + eeprom_word = int32((sync_delay_seed << 24) | (io_update_delay << 16)) eeprom.write_i32(offset, eeprom_word) print("...done") From 3160378614561035829d55f18a37f59063109129 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Wed, 27 Apr 2022 17:31:44 +0800 Subject: [PATCH 185/352] almazny: fix missing (but unused) core --- artiq/coredevice/mirny.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py index 44f08f1dc..9aa7f88d8 100644 --- a/artiq/coredevice/mirny.py +++ b/artiq/coredevice/mirny.py @@ -192,7 +192,8 @@ class Almazny: :param host_mirny - Mirny device Almazny is connected to """ - + + core: KernelInvariant[Core] mirny_cpld: KernelInvariant[Mirny] att_mu: Kernel[list[int32]] channel_sw: Kernel[list[int32]] @@ -200,6 +201,7 @@ class Almazny: def __init__(self, dmgr, host_mirny): self.mirny_cpld = dmgr.get(host_mirny) + self.core = self.mirny_cpld.core self.att_mu = [0x3f] * 4 self.channel_sw = [0] * 4 self.output_enable = False From 50767c036522084650412e5fc36348ebb0099cae Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Apr 2022 18:41:59 +0800 Subject: [PATCH 186/352] examples/kc705_nist_clock: port to NAC3 --- .../examples/kc705_nist_clock/idle_kernel.py | 21 ++++---- .../kc705_nist_clock/repository/core_pause.py | 18 +++++-- .../kc705_nist_clock/repository/dds_setter.py | 10 +++- .../kc705_nist_clock/repository/dds_test.py | 33 +++++++++---- .../kc705_nist_clock/repository/dma_blink.py | 2 + .../kc705_nist_clock/repository/handover.py | 10 +++- .../kc705_nist_clock/repository/mandelbrot.py | 22 ++++++--- .../repository/photon_histogram.py | 48 +++++++++++++------ .../kc705_nist_clock/repository/precompile.py | 2 + .../repository/speed_benchmark.py | 31 ++++++++++-- .../kc705_nist_clock/repository/tdr.py | 47 +++++++++++------- 11 files changed, 175 insertions(+), 69 deletions(-) diff --git a/artiq/examples/kc705_nist_clock/idle_kernel.py b/artiq/examples/kc705_nist_clock/idle_kernel.py index d4d746fd3..964a99674 100644 --- a/artiq/examples/kc705_nist_clock/idle_kernel.py +++ b/artiq/examples/kc705_nist_clock/idle_kernel.py @@ -1,21 +1,26 @@ from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut - +@nac3 class IdleKernel(EnvExperiment): + core: KernelInvariant[Core] + led: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("led") @kernel def run(self): - start_time = now_mu() + self.core.seconds_to_mu(500*ms) + start_time = now_mu() + self.core.seconds_to_mu(500.*ms) while self.core.get_rtio_counter_mu() < start_time: pass self.core.reset() while True: - self.led.pulse(250*ms) - delay(125*ms) - self.led.pulse(125*ms) - delay(125*ms) - self.led.pulse(125*ms) - delay(250*ms) + self.led.pulse(250.*ms) + self.core.delay(125.*ms) + self.led.pulse(125.*ms) + self.core.delay(125.*ms) + self.led.pulse(125.*ms) + self.core.delay(250.*ms) diff --git a/artiq/examples/kc705_nist_clock/repository/core_pause.py b/artiq/examples/kc705_nist_clock/repository/core_pause.py index f483f5f6b..10bb900ab 100644 --- a/artiq/examples/kc705_nist_clock/repository/core_pause.py +++ b/artiq/examples/kc705_nist_clock/repository/core_pause.py @@ -1,20 +1,30 @@ from time import sleep from artiq.experiment import * +from artiq.coredevice.core import Core + +# NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/282 + +@rpc +def sleep_rpc(): + sleep(1) +@nac3 class CorePause(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") self.setattr_device("scheduler") @kernel def k(self): - print("kernel starting") + print_rpc("kernel starting") while not self.scheduler.check_pause(): - print("main kernel loop running...") - sleep(1) - print("kernel exiting") + print_rpc("main kernel loop running...") + sleep_rpc() + print_rpc("kernel exiting") def run(self): while True: diff --git a/artiq/examples/kc705_nist_clock/repository/dds_setter.py b/artiq/examples/kc705_nist_clock/repository/dds_setter.py index 7f4b1447e..de2e11c8e 100644 --- a/artiq/examples/kc705_nist_clock/repository/dds_setter.py +++ b/artiq/examples/kc705_nist_clock/repository/dds_setter.py @@ -1,10 +1,16 @@ from operator import itemgetter from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.ad9914 import AD9914 +@nac3 class DDSSetter(EnvExperiment): """DDS Setter""" + + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") @@ -24,10 +30,10 @@ class DDSSetter(EnvExperiment): } @kernel - def set_dds(self, dds, frequency): + def set_dds(self, dds: AD9914, frequency: float): self.core.break_realtime() dds.set(frequency) - delay(200*ms) + self.core.delay(200.*ms) def run(self): for k, v in self.dds.items(): diff --git a/artiq/examples/kc705_nist_clock/repository/dds_test.py b/artiq/examples/kc705_nist_clock/repository/dds_test.py index dceb10438..9200ba3bf 100644 --- a/artiq/examples/kc705_nist_clock/repository/dds_test.py +++ b/artiq/examples/kc705_nist_clock/repository/dds_test.py @@ -1,9 +1,22 @@ from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.ad9914 import AD9914 +from artiq.coredevice.ttl import TTLOut +@nac3 class DDSTest(EnvExperiment): """DDS test""" + core: KernelInvariant[Core] + dds0: KernelInvariant[AD9914] + dds1: KernelInvariant[AD9914] + dds2: KernelInvariant[AD9914] + ttl0: KernelInvariant[TTLOut] + ttl1: KernelInvariant[TTLOut] + ttl2: KernelInvariant[TTLOut] + led: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.dds0 = self.get_device("ad9914dds0") @@ -17,21 +30,21 @@ class DDSTest(EnvExperiment): @kernel def run(self): self.core.reset() - delay(200*us) - self.dds1.set(120*MHz) - delay(10*us) - self.dds2.set(200*MHz) - delay(1*us) + self.core.delay(200.*us) + self.dds1.set(120.*MHz) + self.core.delay(10.*us) + self.dds2.set(200.*MHz) + self.core.delay(1.*us) for i in range(10000): - if i & 0x200: + if bool(i & 0x200): self.led.on() else: self.led.off() with parallel: with sequential: - self.dds0.set(100*MHz + 4*i*kHz) - self.ttl0.pulse(500*us) - self.ttl1.pulse(500*us) - self.ttl2.pulse(100*us) + self.dds0.set(100.*MHz + 4.*float(i)*kHz) + self.ttl0.pulse(500.*us) + self.ttl1.pulse(500.*us) + self.ttl2.pulse(100.*us) self.led.off() diff --git a/artiq/examples/kc705_nist_clock/repository/dma_blink.py b/artiq/examples/kc705_nist_clock/repository/dma_blink.py index 92c96327c..46cf8cccf 100644 --- a/artiq/examples/kc705_nist_clock/repository/dma_blink.py +++ b/artiq/examples/kc705_nist_clock/repository/dma_blink.py @@ -1,6 +1,8 @@ from artiq.experiment import * +# NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/75 + class DMABlink(EnvExperiment): def build(self): self.setattr_device("core") diff --git a/artiq/examples/kc705_nist_clock/repository/handover.py b/artiq/examples/kc705_nist_clock/repository/handover.py index c63ef8a74..eb1e90391 100644 --- a/artiq/examples/kc705_nist_clock/repository/handover.py +++ b/artiq/examples/kc705_nist_clock/repository/handover.py @@ -1,15 +1,21 @@ from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut +@nac3 class Handover(EnvExperiment): + core: KernelInvariant[Core] + led: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("led") @kernel def blink_once(self): - delay(250*ms) - self.led.pulse(250*ms) + self.core.delay(250.*ms) + self.led.pulse(250.*ms) def run(self): self.core.reset() diff --git a/artiq/examples/kc705_nist_clock/repository/mandelbrot.py b/artiq/examples/kc705_nist_clock/repository/mandelbrot.py index 81e477548..bfe968453 100644 --- a/artiq/examples/kc705_nist_clock/repository/mandelbrot.py +++ b/artiq/examples/kc705_nist_clock/repository/mandelbrot.py @@ -1,17 +1,25 @@ import sys +from numpy import int32 + from artiq.experiment import * +from artiq.coredevice.core import Core +@nac3 class Mandelbrot(EnvExperiment): """Mandelbrot set demo""" + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") - def col(self, i): + @rpc + def col(self, i: int32): sys.stdout.write(" .,-:;i+hHM$*#@ "[i]) + @rpc def row(self): print("") @@ -22,22 +30,22 @@ class Mandelbrot(EnvExperiment): maxX = 1.0 width = 78 height = 36 - aspectRatio = 2 + aspectRatio = 2.0 - yScale = (maxX-minX)*(height/width)*aspectRatio + yScale = (maxX-minX)*(float(height)/float(width))*aspectRatio for y in range(height): for x in range(width): - c_r = minX+x*(maxX-minX)/width - c_i = y*yScale/height-yScale/2 + c_r = minX+float(x)*(maxX-minX)/float(width) + c_i = float(y)*yScale/float(height)-yScale/2.0 z_r = c_r z_i = c_i i = 0 for i in range(16): - if z_r*z_r + z_i*z_i > 4: + if z_r*z_r + z_i*z_i > 4.0: break new_z_r = (z_r*z_r)-(z_i*z_i) + c_r - z_i = 2*z_r*z_i + c_i + z_i = 2.0*z_r*z_i + c_i z_r = new_z_r self.col(i) self.row() diff --git a/artiq/examples/kc705_nist_clock/repository/photon_histogram.py b/artiq/examples/kc705_nist_clock/repository/photon_histogram.py index 4a9166a8a..f4a9be947 100644 --- a/artiq/examples/kc705_nist_clock/repository/photon_histogram.py +++ b/artiq/examples/kc705_nist_clock/repository/photon_histogram.py @@ -1,9 +1,28 @@ +from numpy import int32 + from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.ad9914 import AD9914 +from artiq.coredevice.ttl import TTLOut, TTLInOut +@nac3 class PhotonHistogram(EnvExperiment): """Photon histogram""" + core: KernelInvariant[Core] + bd_dds: KernelInvariant[AD9914] + bd_sw: KernelInvariant[TTLOut] + bdd_dds: KernelInvariant[AD9914] + bdd_sw: KernelInvariant[TTLOut] + pmt: KernelInvariant[TTLInOut] + + nbins: KernelInvariant[int32] + repeats: KernelInvariant[int32] + cool_f: KernelInvariant[float] + detect_f: KernelInvariant[float] + detect_t: KernelInvariant[float] + def build(self): self.setattr_device("core") self.setattr_device("bd_dds") @@ -22,20 +41,21 @@ class PhotonHistogram(EnvExperiment): @kernel def program_cooling(self): delay_mu(-self.bd_dds.set_duration_mu) - self.bd_dds.set(200*MHz) + self.bd_dds.set(200.*MHz) delay_mu(self.bd_dds.set_duration_mu) - self.bdd_dds.set(300*MHz) + self.bdd_dds.set(300.*MHz) @kernel - def cool_detect(self): + def cool_detect(self) -> int32: with parallel: - self.bd_sw.pulse(1*ms) - self.bdd_sw.pulse(1*ms) + self.bd_sw.pulse(1.*ms) + self.bdd_sw.pulse(1.*ms) self.bd_dds.set(self.cool_f) - self.bd_sw.pulse(100*us) + self.bd_sw.pulse(100.*us) self.bd_dds.set(self.detect_f) + gate_end_mu = int64(0) with parallel: self.bd_sw.pulse(self.detect_t) gate_end_mu = self.pmt.gate_rising(self.detect_t) @@ -45,6 +65,11 @@ class PhotonHistogram(EnvExperiment): self.bdd_sw.on() return self.pmt.count(gate_end_mu) + + @rpc + def report(self, hist: list[int32], ion_present: bool): + self.set_dataset("cooling_photon_histogram", hist) + self.set_dataset("ion_present", ion_present, broadcast=True) @kernel def run(self): @@ -55,18 +80,11 @@ class PhotonHistogram(EnvExperiment): total = 0 for i in range(self.repeats): - delay(0.5*ms) + self.core.delay(0.5*ms) n = self.cool_detect() if n >= self.nbins: n = self.nbins - 1 hist[n] += 1 total += n - self.set_dataset("cooling_photon_histogram", hist) - self.set_dataset("ion_present", total > 5*self.repeats, - broadcast=True) - - -if __name__ == "__main__": - from artiq.frontend.artiq_run import run - run() + self.report(hist, total > 5*self.repeats) diff --git a/artiq/examples/kc705_nist_clock/repository/precompile.py b/artiq/examples/kc705_nist_clock/repository/precompile.py index 6bfaaf057..2ac981d25 100644 --- a/artiq/examples/kc705_nist_clock/repository/precompile.py +++ b/artiq/examples/kc705_nist_clock/repository/precompile.py @@ -1,6 +1,8 @@ from artiq.experiment import * +# NAC3TODO + class Precompile(EnvExperiment): def build(self): self.setattr_device("core") diff --git a/artiq/examples/kc705_nist_clock/repository/speed_benchmark.py b/artiq/examples/kc705_nist_clock/repository/speed_benchmark.py index 63b807390..cf28eb70c 100644 --- a/artiq/examples/kc705_nist_clock/repository/speed_benchmark.py +++ b/artiq/examples/kc705_nist_clock/repository/speed_benchmark.py @@ -1,6 +1,9 @@ import time +from numpy import int32 + from artiq.experiment import * +from artiq.coredevice.core import Core class _PayloadNOP(EnvExperiment): @@ -11,7 +14,10 @@ class _PayloadNOP(EnvExperiment): pass +@nac3 class _PayloadCoreNOP(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") @@ -20,11 +26,15 @@ class _PayloadCoreNOP(EnvExperiment): pass +@nac3 class _PayloadCoreSend100Ints(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") - def devnull(self, d): + @rpc + def devnull(self, d: int32): pass @kernel @@ -33,11 +43,15 @@ class _PayloadCoreSend100Ints(EnvExperiment): self.devnull(42) +@nac3 class _PayloadCoreSend1MB(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") - def devnull(self, d): + @rpc + def devnull(self, d: list[int32]): pass @kernel @@ -46,11 +60,15 @@ class _PayloadCoreSend1MB(EnvExperiment): self.devnull(data) +@nac3 class _PayloadCorePrimes(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") - def devnull(self, d): + @rpc + def devnull(self, d: int32): pass @kernel @@ -104,9 +122,14 @@ class SpeedBenchmark(EnvExperiment): def run_without_scheduler(self, pause): payload = globals()["_Payload" + self.payload](self) + start_time = time.monotonic() for i in range(int(self.nruns)): - payload.run() + try: + payload.run() + except: + import traceback + print(traceback.format_exc()) if pause: self.core.comm.close() self.scheduler.pause() diff --git a/artiq/examples/kc705_nist_clock/repository/tdr.py b/artiq/examples/kc705_nist_clock/repository/tdr.py index 21dc9338a..fa0776371 100644 --- a/artiq/examples/kc705_nist_clock/repository/tdr.py +++ b/artiq/examples/kc705_nist_clock/repository/tdr.py @@ -1,24 +1,30 @@ # Copyright (C) 2014, 2015 Robert Jordens +from numpy import int32, int64 + from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut, TTLInOut +@nac3 class PulseNotReceivedError(Exception): pass +@nac3 class TDR(EnvExperiment): """Time domain reflectometer. - From ttl2 an impedance matched pulse is send onto a coax - cable with an open end. pmt0 (very short stub, high impedance) also - listens on the transmission line near ttl2. + From ttl0 an impedance matched pulse is send onto a coax + cable with an open end. ttl3 (very short stub, high impedance) also + listens on the transmission line near ttl0. - When the forward propagating pulse passes pmt0, the voltage is half of the + When the forward propagating pulse passes ttl3, the voltage is half of the logic voltage and does not register as a rising edge. Once the - rising edge is reflected at an open end (same sign) and passes by pmt0 on - its way back to ttl2, it is detected. Analogously, hysteresis leads to - detection of the falling edge once the reflection reaches pmt0 after + rising edge is reflected at an open end (same sign) and passes by ttl3 on + its way back to ttl0, it is detected. Analogously, hysteresis leads to + detection of the falling edge once the reflection reaches ttl3 after one round trip time. This works marginally and is just a proof of principle: it relies on @@ -30,10 +36,17 @@ class TDR(EnvExperiment): This is also equivalent to a loopback tester or a delay measurement. """ + + core: KernelInvariant[Core] + ttl3: KernelInvariant[TTLInOut] + ttl0: KernelInvariant[TTLOut] + + t: Kernel[list[int32]] + def build(self): self.setattr_device("core") - self.setattr_device("pmt0") - self.setattr_device("ttl2") + self.setattr_device("ttl3") + self.setattr_device("ttl0") def run(self): self.core.reset() @@ -54,20 +67,20 @@ class TDR(EnvExperiment): t_rise/1e-9, t_fall/1e-9)) @kernel - def many(self, n, p): + def many(self, n: int32, p: int64): self.core.break_realtime() for i in range(n): self.one(p) @kernel - def one(self, p): + def one(self, p: int64): t0 = now_mu() with parallel: - self.pmt0.gate_both_mu(2*p) - self.ttl2.pulse_mu(p) + self.ttl3.gate_both_mu(int64(2)*p) + self.ttl0.pulse_mu(p) for i in range(len(self.t)): - ti = self.pmt0.timestamp_mu(now_mu()) - if ti <= 0: + ti = self.ttl3.timestamp_mu(now_mu()) + if ti <= int64(0): raise PulseNotReceivedError() - self.t[i] = int(self.t[i] + ti - t0) - self.pmt0.count(now_mu()) # flush + self.t[i] = int32(int64(self.t[i]) + ti - t0) + self.ttl3.count(now_mu()) # flush From a1651d15f54287490924a08eb194966356431ef6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Apr 2022 15:27:42 +0800 Subject: [PATCH 187/352] urukul: _RegIOUpdate fixes --- artiq/coredevice/urukul.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 769c31ab3..d4e04ca70 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from numpy import int32, int64 from artiq.language.core import * @@ -427,6 +429,8 @@ class CPLD: cfg |= (profile & 7) << CFG_PROFILE self.cfg_write(cfg) + +@nac3 class _RegIOUpdate: core: KernelInvariant[Core] cpld: KernelInvariant[CPLD] @@ -436,8 +440,12 @@ class _RegIOUpdate: self.cpld = cpld @kernel - def pulse(self, t: float): + def pulse_mu(self, t: int64): cfg = self.cpld.cfg_reg self.cpld.cfg_write(cfg | (1 << CFG_IO_UPDATE)) - delay(t) + delay_mu(t) self.cpld.cfg_write(cfg) + + @kernel + def pulse(self, t: float): + self.pulse_mu(self.core.seconds_to_mu(t)) From 49cb570290947536297dcbe5fccb37e85bf1b4bf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Apr 2022 15:28:07 +0800 Subject: [PATCH 188/352] examples/kasli_suservo: port to NAC3 --- .../kasli_suservo/repository/suservo.py | 70 +++++++++++-------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py index 7bc887030..c79ab6046 100644 --- a/artiq/examples/kasli_suservo/repository/suservo.py +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -1,7 +1,24 @@ +from numpy import int32 + from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut +from artiq.coredevice.suservo import SUServo, Channel as SUServoChannel +@nac3 +class SUServoDemo(EnvExperiment): + core: KernelInvariant[Core] + led0: KernelInvariant[TTLOut] + suservo0: KernelInvariant[SUServo] + suservo0_ch0: KernelInvariant[SUServoChannel] + suservo0_ch1: KernelInvariant[SUServoChannel] + suservo0_ch2: KernelInvariant[SUServoChannel] + suservo0_ch3: KernelInvariant[SUServoChannel] + suservo0_ch4: KernelInvariant[SUServoChannel] + suservo0_ch5: KernelInvariant[SUServoChannel] + suservo0_ch6: KernelInvariant[SUServoChannel] + suservo0_ch7: KernelInvariant[SUServoChannel] -class SUServo(EnvExperiment): def build(self): self.setattr_device("core") self.setattr_device("led0") @@ -9,40 +26,37 @@ class SUServo(EnvExperiment): for i in range(8): self.setattr_device("suservo0_ch{}".format(i)) - def run(self): - self.init() - - def p(self, d): + @rpc + def p(self, d: list[int32]): mask = 1 << 18 - 1 for name, val in zip("ftw1 b1 pow cfg offset a1 ftw0 b0".split(), d): val = -(val & mask) + (val & ~mask) print("{}: {:#x} = {}".format(name, val, val)) - @rpc(flags={"async"}) - def p1(self, adc, asf, st): + @rpc # NAC3TODO (flags={"async"}) + def p1(self, adc: float, asf: float, st: int32): print("ADC: {:10s}, ASF: {:10s}, clipped: {}".format( "#"*int(adc), "#"*int(asf*10), (st >> 8) & 1), end="\r") @kernel - def init(self): - self.core.break_realtime() + def run(self): self.core.reset() self.led() self.suservo0.init() - delay(1*us) + self.core.delay(1.*us) # ADC PGIA gain for i in range(8): self.suservo0.set_pgia_mu(i, 0) - delay(10*us) + self.core.delay(10.*us) # DDS attenuator - self.suservo0.cpld0.set_att(0, 10.) - delay(1*us) + self.suservo0.cplds[0].set_att(0, 10.) + self.core.delay(1.*us) # Servo is done and disabled assert self.suservo0.get_status() & 0xff == 2 # set up profile 0 on channel 0: - delay(120*us) + self.core.delay(120.*us) self.suservo0_ch0.set_y( profile=0, y=0. # clear integrator @@ -61,39 +75,39 @@ class SUServo(EnvExperiment): self.suservo0_ch0.set_dds( profile=0, offset=-.5, # 5 V with above PGIA settings - frequency=71*MHz, + frequency=71.*MHz, phase=0.) # enable RF, IIR updates and profile 0 - self.suservo0_ch0.set(en_out=1, en_iir=1, profile=0) + self.suservo0_ch0.set(en_out=True, en_iir=True, profile=0) # enable global servo iterations - self.suservo0.set_config(enable=1) + self.suservo0.set_config(enable=True) # check servo enabled assert self.suservo0.get_status() & 0x01 == 1 - delay(10*us) + self.core.delay(10.*us) # read back profile data - data = [0] * 8 + data = [0 for _ in range(8)] self.suservo0_ch0.get_profile_mu(0, data) self.p(data) - delay(10*ms) + self.core.delay(10.*ms) while True: - self.suservo0.set_config(0) - delay(10*us) + self.suservo0.set_config(False) + self.core.delay(10.*us) v = self.suservo0.get_adc(7) - delay(30*us) + self.core.delay(30.*us) w = self.suservo0_ch0.get_y(0) - delay(20*us) + self.core.delay(20.*us) x = self.suservo0.get_status() - delay(10*us) - self.suservo0.set_config(1) + self.core.delay(10.*us) + self.suservo0.set_config(True) self.p1(v, w, x) - delay(20*ms) + self.core.delay(20.*ms) @kernel def led(self): self.core.break_realtime() for i in range(3): self.led0.pulse(.1*s) - delay(.1*s) + self.core.delay(.1*s) From 8e594d6666fa40b88f6b06016fd06c459719cb1f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Apr 2022 15:37:30 +0800 Subject: [PATCH 189/352] language/core: forward kernel return value --- artiq/language/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/language/core.py b/artiq/language/core.py index e1dc7f0ec..cb1908d26 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -76,7 +76,7 @@ def kernel(function_or_method): @wraps(function_or_method) def run_on_core(self, *args, **kwargs): fake_method = SimpleNamespace(__self__=self, __name__=function_or_method.__name__) - self.core.run(fake_method, args, kwargs) + return self.core.run(fake_method, args, kwargs) else: @wraps(function_or_method) def run_on_core(*args, **kwargs): From 5504177d489343a470a3c4399cfdbf65e1be62ed Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Apr 2022 15:37:44 +0800 Subject: [PATCH 190/352] sim: fix imports --- artiq/sim/devices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/sim/devices.py b/artiq/sim/devices.py index fc258ed48..7704bb1a6 100644 --- a/artiq/sim/devices.py +++ b/artiq/sim/devices.py @@ -1,6 +1,6 @@ from random import Random -from artiq.language.core import kernel, sequential, delay_mu +from artiq.language.core import kernel, sequential, at_mu, delay_mu from artiq.sim import time From fc95dffd0b879f5d49213971815e9d13ccd0f419 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Apr 2022 15:38:19 +0800 Subject: [PATCH 191/352] examples/no_hardware: port to NAC3 --- .../examples/no_hardware/repository/al_spectroscopy.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/examples/no_hardware/repository/al_spectroscopy.py b/artiq/examples/no_hardware/repository/al_spectroscopy.py index d48c2ead7..8566dc11a 100644 --- a/artiq/examples/no_hardware/repository/al_spectroscopy.py +++ b/artiq/examples/no_hardware/repository/al_spectroscopy.py @@ -22,17 +22,17 @@ class AluminumSpectroscopy(EnvExperiment): for count in range(100): self.mains_sync.gate_rising(1*s/60) at_mu(self.mains_sync.timestamp_mu(now_mu()) + 100*us) - delay(10*us) + self.core.delay(10.*us) self.laser_cooling.pulse(100*MHz, 100*us) - delay(5*us) + self.core.delay(5.*us) with parallel: self.spectroscopy.pulse(self.spectroscopy_freq, 100*us) with sequential: - delay(50*us) + self.core.delay(50.*us) self.spectroscopy_b.set(200) - delay(5*us) + self.core.delay(5.*us) while True: - delay(5*us) + self.core.delay(5.*us) with parallel: self.state_detection.pulse(100*MHz, 10*us) photon_count = self.pmt.count(self.pmt.gate_rising(10*us)) From fb8c13b5411dd92e90d8476643cc301c35ea6608 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 14 May 2022 16:34:27 +0800 Subject: [PATCH 192/352] flake: update dependencies --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 4315f26f3..721027070 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1651045306, - "narHash": "sha256-YNrfAwepqN4Fv5tTLzuZeKEEFvY1uL25IC2wQAQPf40=", + "lastModified": 1652517183, + "narHash": "sha256-qBd96qgLAMb68jczwkyTUQM5t7ktBaHTjP1OY7wsW7M=", "ref": "master", - "rev": "3f327113b25ce34519fe686bd5531ef0efa31e27", - "revCount": 763, + "rev": "b9259b1907261b13424b45354f3ee6b068c5c1db", + "revCount": 768, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,11 +60,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1650921206, - "narHash": "sha256-RGlfTC2ktqLVw0gBvZeCM//B4ig2CdQJm39sDvm0DBQ=", + "lastModified": 1652442528, + "narHash": "sha256-ctD9BdjN7e6cBipm8k9xt+vgwlRApkvuJLSNdaVrphE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3a9e0f239d80fa134e8fcbdee4dfc793902da37e", + "rev": "79385ae0aacf7e02871cc8af0623123419dd7884", "type": "github" }, "original": { @@ -92,11 +92,11 @@ ] }, "locked": { - "lastModified": 1649724535, - "narHash": "sha256-15Nun4EY35j+6SPZkjzZtyH/ncxLS60KuGJjFh5kSTc=", + "lastModified": 1651624017, + "narHash": "sha256-engReD8l4xzQQJP8BJ7gILUyA1KH5d60lexDVfnoiRM=", "owner": "m-labs", "repo": "sipyco", - "rev": "939f84f9b5eef7efbf7423c735d1834783b6140e", + "rev": "efda015e9994faf6cafc19b239d8e69ca4d26226", "type": "github" }, "original": { From 1b348dc0025272d88ec19d57669434b0210983dd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 May 2022 12:07:23 +0800 Subject: [PATCH 193/352] flake: update NAC3 --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 721027070..7b9c82795 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1652517183, - "narHash": "sha256-qBd96qgLAMb68jczwkyTUQM5t7ktBaHTjP1OY7wsW7M=", + "lastModified": 1652760312, + "narHash": "sha256-CPbFV/V3qBPFv34EcmjVGAslS824ECyg2fIizlH6BWQ=", "ref": "master", - "rev": "b9259b1907261b13424b45354f3ee6b068c5c1db", - "revCount": 768, + "rev": "0ec2ed4d915e38f73c834c9f40147a3f601f3d8c", + "revCount": 770, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,11 +60,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1652442528, - "narHash": "sha256-ctD9BdjN7e6cBipm8k9xt+vgwlRApkvuJLSNdaVrphE=", + "lastModified": 1652559422, + "narHash": "sha256-jPVTNImBTUIFdtur+d4IVot6eXmsvtOcBm0TzxmhWPk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "79385ae0aacf7e02871cc8af0623123419dd7884", + "rev": "8b3398bc7587ebb79f93dfeea1b8c574d3c6dba1", "type": "github" }, "original": { From 32d4c520f79db197f8d56edd985785c1ed372f75 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 24 May 2022 11:12:30 +0800 Subject: [PATCH 194/352] flake: update dependencies --- flake.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/flake.lock b/flake.lock index 7b9c82795..63cf9b83c 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1652760312, - "narHash": "sha256-CPbFV/V3qBPFv34EcmjVGAslS824ECyg2fIizlH6BWQ=", + "lastModified": 1653361829, + "narHash": "sha256-0V7jQ3q6CAW7V7PySRA6wbsrAQ+0/EUML9+pfToE52o=", "ref": "master", - "rev": "0ec2ed4d915e38f73c834c9f40147a3f601f3d8c", - "revCount": 770, + "rev": "b04631e935ac3264b0a5ef4ebba7141f3e0d2d0c", + "revCount": 772, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,16 +60,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1652559422, - "narHash": "sha256-jPVTNImBTUIFdtur+d4IVot6eXmsvtOcBm0TzxmhWPk=", + "lastModified": 1653354321, + "narHash": "sha256-AMUhX1Ch0KMDWCze6KAntwlJ1iFp0fLK2TTW9Mj85WY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8b3398bc7587ebb79f93dfeea1b8c574d3c6dba1", + "rev": "b80531b35cbcddcaf74ceb685b3a0847c134cbe1", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-21.11", + "ref": "release-22.05", "repo": "nixpkgs", "type": "github" } From 09e786ed3f0db4031200d6f11e3c349fef891c51 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 24 May 2022 11:15:23 +0800 Subject: [PATCH 195/352] msys2: add python-tqdm dependency --- windows/PKGBUILD.artiq | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/PKGBUILD.artiq b/windows/PKGBUILD.artiq index 0a82f71e0..2a03ed575 100644 --- a/windows/PKGBUILD.artiq +++ b/windows/PKGBUILD.artiq @@ -13,6 +13,7 @@ depends=( "mingw-w64-x86_64-python-scipy" "mingw-w64-x86_64-python-dateutil" "mingw-w64-x86_64-python-prettytable" + "mingw-w64-x86_64-python-tqdm" "mingw-w64-x86_64-python-pygit2" "mingw-w64-x86_64-python-sipyco" "mingw-w64-x86_64-nac3artiq" From abe6b01191517f69d7fd96143fadd293526d8d93 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 24 May 2022 11:30:37 +0800 Subject: [PATCH 196/352] flake: fix openocd build --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index f8e53232e..047729ba6 100644 --- a/flake.nix +++ b/flake.nix @@ -254,7 +254,7 @@ sha256 = "sha256-YgUsl4/FohfsOncM4uiz/3c6g2ZN4oZ0y5vV/2Skwqg="; fetchSubmodules = true; }; - patches = oa.patches or [] ++ [ + patches = [ (pkgs.fetchurl { url = "https://git.m-labs.hk/M-Labs/nix-scripts/raw/commit/575ef05cd554c239e4cc8cb97ae4611db458a80d/artiq-fast/pkgs/openocd-jtagspi.diff"; sha256 = "0g3crk8gby42gm661yxdcgapdi8sp050l5pb2d0yjfic7ns9cw81"; From c7b8dcac491c1c2c507f644224978d1f5464a7dc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 27 May 2022 15:28:47 +0800 Subject: [PATCH 197/352] flake: update dependencies --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 63cf9b83c..611e6aad4 100644 --- a/flake.lock +++ b/flake.lock @@ -11,11 +11,11 @@ ] }, "locked": { - "lastModified": 1649124276, - "narHash": "sha256-l1+vk7cvj4cjl83wRx/y1Jwdds4e8xAzpxHrXusEZ5A=", + "lastModified": 1653635602, + "narHash": "sha256-8Osaeuo5/Yq4sU4mhsIXwmy7ZX3iDBbAAZF3lu1+KdQ=", "owner": "m-labs", "repo": "artiq-comtools", - "rev": "e2d85f2e51ecdac463da752ef754e59572f9e119", + "rev": "accc6dd0ca1c1c240b906b14c5cb13098a14906b", "type": "github" }, "original": { @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1653361829, - "narHash": "sha256-0V7jQ3q6CAW7V7PySRA6wbsrAQ+0/EUML9+pfToE52o=", + "lastModified": 1653596629, + "narHash": "sha256-3mKHjaIh1XUTo0nzXoBv5wX34hY8wevVxnVaXtqPnjQ=", "ref": "master", - "rev": "b04631e935ac3264b0a5ef4ebba7141f3e0d2d0c", - "revCount": 772, + "rev": "76473152e88867a2c9cc1afa58de7f17c72054ba", + "revCount": 773, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -92,11 +92,11 @@ ] }, "locked": { - "lastModified": 1651624017, - "narHash": "sha256-engReD8l4xzQQJP8BJ7gILUyA1KH5d60lexDVfnoiRM=", + "lastModified": 1653633179, + "narHash": "sha256-xyHQ77RXI9Zq9is+9laArq1HnlyubozL+Ht9BEQGXow=", "owner": "m-labs", "repo": "sipyco", - "rev": "efda015e9994faf6cafc19b239d8e69ca4d26226", + "rev": "438f649864c58fa2eb213030a336864bba3a18a8", "type": "github" }, "original": { From 6ac7aced344bf41335093d362efc1bd064a4f7a2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 27 May 2022 15:32:47 +0800 Subject: [PATCH 198/352] windows: use upstream pyqtgraph and qasync --- flake.nix | 2 -- windows/PKGBUILD.pyqtgraph | 11 ----------- windows/PKGBUILD.qasync | 11 ----------- windows/default.nix | 12 ------------ 4 files changed, 36 deletions(-) delete mode 100644 windows/PKGBUILD.pyqtgraph delete mode 100644 windows/PKGBUILD.qasync diff --git a/flake.nix b/flake.nix index 047729ba6..5e224581f 100644 --- a/flake.nix +++ b/flake.nix @@ -367,8 +367,6 @@ hydraJobs = { inherit (packages.x86_64-linux) artiq artiq-board-kc705-nist_clock openocd-bscanspi; - qasync-msys2-pkg = packages.x86_64-w64-mingw32.qasync-pkg; - pyqtgraph-msys2-pkg = packages.x86_64-w64-mingw32.pyqtgraph-pkg; sipyco-msys2-pkg = packages.x86_64-w64-mingw32.sipyco-pkg; artiq-comtools-msys2-pkg = packages.x86_64-w64-mingw32.artiq-comtools-pkg; artiq-msys2-pkg = packages.x86_64-w64-mingw32.artiq-pkg; diff --git a/windows/PKGBUILD.pyqtgraph b/windows/PKGBUILD.pyqtgraph deleted file mode 100644 index ab090c3ef..000000000 --- a/windows/PKGBUILD.pyqtgraph +++ /dev/null @@ -1,11 +0,0 @@ -pkgbase="mingw-w64-python-pyqtgraph" -pkgname="mingw-w64-x86_64-python-pyqtgraph" -pkgrel=1 -pkgdesc="Fast data visualization and GUI tools for scientific / engineering applications" -license=("MIT") -depends=( - "mingw-w64-x86_64-python" - "mingw-w64-x86_64-python-pyqt5" -) - -source PKGBUILD.common diff --git a/windows/PKGBUILD.qasync b/windows/PKGBUILD.qasync deleted file mode 100644 index e871cc52f..000000000 --- a/windows/PKGBUILD.qasync +++ /dev/null @@ -1,11 +0,0 @@ -pkgbase="mingw-w64-python-qasync" -pkgname="mingw-w64-x86_64-python-qasync" -pkgrel=1 -pkgdesc="Implementation of the PEP 3156 Event-Loop with Qt" -license=("BSD") -depends=( - "mingw-w64-x86_64-python" - "mingw-w64-x86_64-python-pyqt5" -) - -source PKGBUILD.common diff --git a/windows/default.nix b/windows/default.nix index 8f4a48a1b..68b764fb0 100644 --- a/windows/default.nix +++ b/windows/default.nix @@ -28,16 +28,6 @@ let ''; }; in rec { - qasync-pkg = makeMsys2 { - name = "qasync"; - src = artiq.packages.x86_64-linux.qasync.src; - inherit (artiq.packages.x86_64-linux.qasync) version; - }; - pyqtgraph-pkg = makeMsys2 { - name = "pyqtgraph"; - src = pkgs.python3Packages.pyqtgraph.src; - inherit (pkgs.python3Packages.pyqtgraph) version; - }; sipyco-pkg = makeMsys2 { name = "sipyco"; src = sipyco; @@ -61,8 +51,6 @@ in rec { '' mkdir $out cd $out - ln -s ${qasync-pkg}/*.pkg.tar.zst . - ln -s ${pyqtgraph-pkg}/*.pkg.tar.zst . ln -s ${sipyco-pkg}/*.pkg.tar.zst . ln -s ${artiq-comtools-pkg}/*.pkg.tar.zst . ln -s ${nac3.packages.x86_64-w64-mingw32.nac3artiq-pkg}/*.pkg.tar.zst . From 2c7c2d0e3db432357c64ce99e062ce1326e27d0c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 27 May 2022 15:33:51 +0800 Subject: [PATCH 199/352] windows: add pybase64 dependency --- windows/PKGBUILD.sipyco | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/PKGBUILD.sipyco b/windows/PKGBUILD.sipyco index dddeb4a34..7430d590e 100644 --- a/windows/PKGBUILD.sipyco +++ b/windows/PKGBUILD.sipyco @@ -6,7 +6,7 @@ license=("LGPL") depends=( "mingw-w64-x86_64-python" "mingw-w64-x86_64-python-numpy" - # TODO "mingw-w64-x86_64-python-pybase64" + "mingw-w64-x86_64-python-pybase64" ) source PKGBUILD.common From 7c3d9bb376c9c5983715ab601ffb5168330e1edc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 27 May 2022 15:35:01 +0800 Subject: [PATCH 200/352] doc: remove unnecessary builtins.__in_sphinx__ hack --- doc/manual/conf.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/doc/manual/conf.py b/doc/manual/conf.py index 61680750c..d8278d61b 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -20,12 +20,6 @@ from unittest.mock import Mock import sphinx_rtd_theme -# Ensure that ARTIQ-Python types are correctly printed -# See: https://github.com/m-labs/artiq/issues/741 -import builtins -builtins.__in_sphinx__ = True - - # we cannot use autodoc_mock_imports (does not help with argparse) mock_modules = ["artiq.gui.waitingspinnerwidget", "artiq.gui.flowlayout", From 5d7b01bd3fdda5d0f18549c961e6c017b3cbf5e5 Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 1 Jun 2022 12:23:29 +0800 Subject: [PATCH 201/352] dyld: rename pltrel to jmprel nac3ld will not generate PLT & its relocation section. There might not be a pltrel in that case. On the other hand, rebinding will not be limited to the symbols in the PLT when linked with nac3ld. Thus the renaming. --- artiq/firmware/libdyld/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libdyld/lib.rs b/artiq/firmware/libdyld/lib.rs index 1d89edaee..9d906034f 100644 --- a/artiq/firmware/libdyld/lib.rs +++ b/artiq/firmware/libdyld/lib.rs @@ -86,7 +86,7 @@ pub struct Library<'a> { image_sz: usize, strtab: &'a [u8], symtab: &'a [Elf32_Sym], - pltrel: &'a [Elf32_Rela], + jmprel: &'a [Elf32_Rela], hash_bucket: &'a [Elf32_Word], hash_chain: &'a [Elf32_Word], } @@ -136,9 +136,9 @@ impl<'a> Library<'a> { Ok(unsafe { *ptr = value }) } - // This is unsafe because it mutates global data (the PLT). + // This is unsafe because it mutates global data (instructions). pub unsafe fn rebind(&self, name: &[u8], addr: Elf32_Word) -> Result<(), Error<'a>> { - for rela in self.pltrel.iter() { + for rela in self.jmprel.iter() { match ELF32_R_TYPE(rela.r_info) { R_RISCV_32 | R_RISCV_JUMP_SLOT => { let sym = self.symtab.get(ELF32_R_SYM(rela.r_info) as usize) @@ -328,7 +328,7 @@ impl<'a> Library<'a> { image_sz: image.len(), strtab: strtab, symtab: symtab, - pltrel: pltrel, + jmprel: if pltrel.is_empty() { rela } else { pltrel }, hash_bucket: &hash[..nbucket], hash_chain: &hash[nbucket..nbucket + nchain], }; From 2cd43bf4f7315a1faf0cd34f44fa97b8a473006c Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 1 Jun 2022 12:30:56 +0800 Subject: [PATCH 202/352] dyld: support additional RV32 reloc types The support of LO12 type requires the runtime linker to find the corresponding HI20 symbol. resolve_rela needs the entire relocation section for that. --- artiq/firmware/libdyld/lib.rs | 100 +++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/artiq/firmware/libdyld/lib.rs b/artiq/firmware/libdyld/lib.rs index 9d906034f..9ace28ed4 100644 --- a/artiq/firmware/libdyld/lib.rs +++ b/artiq/firmware/libdyld/lib.rs @@ -133,7 +133,36 @@ impl<'a> Library<'a> { } let ptr = (self.image_off + rela.r_offset) as *mut Elf32_Addr; - Ok(unsafe { *ptr = value }) + + match ELF32_R_TYPE(rela.r_info) { + R_RISCV_RELATIVE | R_RISCV_32 | R_RISCV_JUMP_SLOT => Ok(unsafe { *ptr = value }), + + R_RISCV_CALL_PLT => { + Ok(unsafe { + *ptr = (*ptr & 0xFFF) | ((value + 0x800) & 0xFFFFF000); + *(ptr.offset(1)) = (*(ptr.offset(1)) & 0xFFFFF) | ((value & 0xFFF) << 20); + }) + } + + R_RISCV_GOT_HI20 => { + Ok(unsafe { + *ptr = (*ptr & 0xFFF) | ((value + 0x800) & 0xFFFFF000) + }) + } + + // We will not use indirect addressing here + // So, just put in the direct address instead of the GOT + // The lower instruction must be changed to addi (typically from lw) + // to make the value treated as the direct address + // Hex encoding of addi (opcode/funct3): 0x13/0 + R_RISCV_PCREL_LO12_I => { + Ok(unsafe { + *ptr = (*ptr & 0xF8F80) | 0x13 | ((value & 0xFFF) << 20); + }) + } + + _ => Err(Error::Parsing("Unsupported relocation")) + } } // This is unsafe because it mutates global data (instructions). @@ -157,35 +186,28 @@ impl<'a> Library<'a> { Ok(()) } - fn resolve_rela(&self, rela: &Elf32_Rela, resolve: &dyn Fn(&[u8]) -> Option) + fn resolve_rela(&self, relas: &[Elf32_Rela], resolve: &dyn Fn(&[u8]) -> Option) -> Result<(), Error<'a>> { - let sym; - if ELF32_R_SYM(rela.r_info) == 0 { - sym = None; - } else { - sym = Some(self.symtab.get(ELF32_R_SYM(rela.r_info) as usize) - .ok_or("symbol out of bounds of symbol table")?) - } + for rela in relas { + let sym; + if ELF32_R_SYM(rela.r_info) == 0 { + sym = None; + } else { + sym = Some(self.symtab.get(ELF32_R_SYM(rela.r_info) as usize) + .ok_or("symbol out of bounds of symbol table")?) + } - let value; - match ELF32_R_TYPE(rela.r_info) { - R_RISCV_NONE => - return Ok(()), - - R_RISCV_RELATIVE => - value = self.image_off + rela.r_addend as Elf32_Word, - - R_RISCV_32 | R_RISCV_JUMP_SLOT => { + let get_symbol_value = |sym: Option<&Elf32_Sym>| { let sym = sym.ok_or("relocation requires an associated symbol")?; let sym_name = self.name_starting_at(sym.st_name as usize)?; // First, try to resolve against itself. match self.lookup(sym_name) { - Some(addr) => value = addr, + Some(addr) => Ok(addr), None => { // Second, call the user-provided function. match resolve(sym_name) { - Some(addr) => value = addr, + Some(addr) => Ok(addr), None => { // We couldn't find it anywhere. return Err(Error::Lookup(sym_name)) @@ -193,12 +215,40 @@ impl<'a> Library<'a> { } } } - } + }; - _ => return Err("unsupported relocation type")? + let value = match ELF32_R_TYPE(rela.r_info) { + R_RISCV_NONE => + return Ok(()), + + R_RISCV_RELATIVE => + self.image_off + rela.r_addend as Elf32_Word, + + R_RISCV_32 | R_RISCV_JUMP_SLOT => { + get_symbol_value(sym)? + } + + R_RISCV_CALL_PLT | R_RISCV_GOT_HI20 => { + let reloc_value = get_symbol_value(sym)?; + reloc_value + rela.r_addend as Elf32_Word - (self.image_off + rela.r_offset) + } + + R_RISCV_PCREL_LO12_I => { + let hi20_reloc_addr = get_symbol_value(sym)?; + let hi20_rela = relas.iter().find(|rela| rela.r_offset == (hi20_reloc_addr - self.image_off)) + .ok_or("corresponding HI20 relocation not found")?; + + let hi20_sym = self.symtab.get(ELF32_R_SYM(hi20_rela.r_info) as usize); + get_symbol_value(hi20_sym)? - hi20_reloc_addr + } + + _ => return Err("unsupported relocation type")? + }; + + self.update_rela(rela, value)?; } - self.update_rela(rela, value) + Ok(()) } pub fn load(data: &[u8], image: &'a mut [u8], resolve: &dyn Fn(&[u8]) -> Option) @@ -343,8 +393,8 @@ impl<'a> Library<'a> { // we never write to the memory they refer to, so it's safe. mem::drop(image); - for r in rela { library.resolve_rela(r, resolve)? } - for r in pltrel { library.resolve_rela(r, resolve)? } + library.resolve_rela(rela, resolve)?; + library.resolve_rela(pltrel, resolve)?; Ok(library) } From d924bfc958b92ea8ce8bbfd9253bfc1d4c72cb0b Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 1 Jun 2022 12:33:40 +0800 Subject: [PATCH 203/352] dyld: handle rebind on symbols relocated by CALL_PLT --- artiq/firmware/libdyld/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/artiq/firmware/libdyld/lib.rs b/artiq/firmware/libdyld/lib.rs index 9ace28ed4..15bbe2548 100644 --- a/artiq/firmware/libdyld/lib.rs +++ b/artiq/firmware/libdyld/lib.rs @@ -179,6 +179,16 @@ impl<'a> Library<'a> { } } + R_RISCV_CALL_PLT => { + let sym = self.symtab.get(ELF32_R_SYM(rela.r_info) as usize) + .ok_or("symbol out of bounds of symbol table")?; + let sym_name = self.name_starting_at(sym.st_name as usize)?; + + if sym_name == name { + self.update_rela(rela, addr - (self.image_off + rela.r_offset))? + } + } + // No associated symbols for other relocation types. _ => () } From 77fd47b1fb0fae7a01799e27bfa39f076ae8adc8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Jun 2022 18:49:23 +0800 Subject: [PATCH 204/352] flake: remove libartiq-support --- flake.nix | 3 --- 1 file changed, 3 deletions(-) diff --git a/flake.nix b/flake.nix index 2fd7a59d0..f30fa34fb 100644 --- a/flake.nix +++ b/flake.nix @@ -360,9 +360,6 @@ pkgs.python3Packages.sphinx pkgs.python3Packages.sphinx_rtd_theme pkgs.python3Packages.sphinx-argparse sphinxcontrib-wavedrom latex-artiq-manual ]; - shellHook = '' - export LIBARTIQ_SUPPORT=`libartiq-support` - ''; }; hydraJobs = { From 0607743669d8840b122da0f9d9ae83faba33699d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Jun 2022 18:49:49 +0800 Subject: [PATCH 205/352] flake: update NAC3, move to LLVM 14, remove LLD --- flake.lock | 28 ++++++++++++++-------------- flake.nix | 22 +++++++++++----------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/flake.lock b/flake.lock index 611e6aad4..3c1693632 100644 --- a/flake.lock +++ b/flake.lock @@ -11,11 +11,11 @@ ] }, "locked": { - "lastModified": 1653635602, - "narHash": "sha256-8Osaeuo5/Yq4sU4mhsIXwmy7ZX3iDBbAAZF3lu1+KdQ=", + "lastModified": 1654007592, + "narHash": "sha256-vaDFhE1ItjqtIcinC/6RAJGbj44pxxMUEeQUa3FtgEE=", "owner": "m-labs", "repo": "artiq-comtools", - "rev": "accc6dd0ca1c1c240b906b14c5cb13098a14906b", + "rev": "cb73281154656ee8f74db1866859e31bf42755cd", "type": "github" }, "original": { @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1653596629, - "narHash": "sha256-3mKHjaIh1XUTo0nzXoBv5wX34hY8wevVxnVaXtqPnjQ=", + "lastModified": 1654510461, + "narHash": "sha256-YWtJOQ5XsJGWBX1AihD03a+m/OHtG2bdhjFmx18NdRY=", "ref": "master", - "rev": "76473152e88867a2c9cc1afa58de7f17c72054ba", - "revCount": 773, + "rev": "8e6e4d6715bdfa4a5639068e4a78e89b714fb8d7", + "revCount": 787, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,16 +60,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1653354321, - "narHash": "sha256-AMUhX1Ch0KMDWCze6KAntwlJ1iFp0fLK2TTW9Mj85WY=", + "lastModified": 1654360807, + "narHash": "sha256-wYG86PUkPZ1P/oHsCpepTkb/U26poaEPPp1XFjRsgdA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b80531b35cbcddcaf74ceb685b3a0847c134cbe1", + "rev": "d9794b04bffb468b886c553557489977ae5f4c65", "type": "github" }, "original": { "owner": "NixOS", - "ref": "release-22.05", + "ref": "nixos-22.05", "repo": "nixpkgs", "type": "github" } @@ -92,11 +92,11 @@ ] }, "locked": { - "lastModified": 1653633179, - "narHash": "sha256-xyHQ77RXI9Zq9is+9laArq1HnlyubozL+Ht9BEQGXow=", + "lastModified": 1654009659, + "narHash": "sha256-/X4gbvqbth0B8lYFZNp1WyJ18N3uJakjLGuWTkRPLMQ=", "owner": "m-labs", "repo": "sipyco", - "rev": "438f649864c58fa2eb213030a336864bba3a18a8", + "rev": "d2359ebf43e5283b44d7d40c76382463be4b76f6", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index f30fa34fb..3bd832db8 100644 --- a/flake.nix +++ b/flake.nix @@ -84,8 +84,8 @@ ''; nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; - # keep llvm_x and lld_x in sync with nac3 - propagatedBuildInputs = [ pkgs.llvm_13 pkgs.lld_13 nac3.packages.x86_64-linux.nac3artiq-pgo sipyco.packages.x86_64-linux.sipyco artiq-comtools.packages.x86_64-linux.artiq-comtools ] + # keep llvm_x in sync with nac3 + propagatedBuildInputs = [ pkgs.llvm_14 nac3.packages.x86_64-linux.nac3artiq-pgo sipyco.packages.x86_64-linux.sipyco artiq-comtools.packages.x86_64-linux.artiq-comtools ] ++ (with pkgs.python3Packages; [ pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial h5py pyqt5 qasync ]); dontWrapQtApps = true; @@ -102,8 +102,8 @@ "--set FONTCONFIG_FILE ${pkgs.fontconfig.out}/etc/fonts/fonts.conf" ]; - # FIXME: automatically propagate lld_13 llvm_13 dependencies - checkInputs = [ pkgs.lld_13 pkgs.llvm_13 ]; + # FIXME: automatically propagate llvm_x dependency + checkInputs = [ pkgs.llvm_14 ]; checkPhase = '' python -m unittest discover -v artiq.test ''; @@ -183,12 +183,12 @@ }; }; nativeBuildInputs = [ - (pkgs.python3.withPackages(ps: [ ps.jsonschema migen misoc artiq])) + (pkgs.python3.withPackages(ps: [ ps.jsonschema migen misoc artiq])) rustPlatform.rust.rustc rustPlatform.rust.cargo - pkgs.llvmPackages_13.clang-unwrapped - pkgs.llvm_13 - pkgs.lld_13 + pkgs.llvmPackages_14.clang-unwrapped + pkgs.llvm_14 + pkgs.lld_14 vivado rustPlatform.cargoSetupHook cargo-xbuild @@ -350,9 +350,9 @@ rustPlatform.rust.rustc rustPlatform.rust.cargo cargo-xbuild - pkgs.llvmPackages_13.clang-unwrapped - pkgs.llvm_13 - pkgs.lld_13 + pkgs.llvmPackages_14.clang-unwrapped + pkgs.llvm_14 + pkgs.lld_14 # use the vivado-env command to enter a FHS shell that lets you run the Vivado installer packages.x86_64-linux.vivadoEnv packages.x86_64-linux.vivado From cb68ed9f1db093641695e5ab8f8cb2b9bb492d08 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Jun 2022 22:45:36 +0800 Subject: [PATCH 206/352] test: remove lit tests --- artiq/test/lit/embedding/syscall_arg_attrs.py | 30 ------------- .../try_finally_while_try_finally_break.py | 42 ------------------- .../try_loop/try_finally_while_try_reraise.py | 42 ------------------- .../try_loop/try_finally_while_try_return.py | 29 ------------- 4 files changed, 143 deletions(-) delete mode 100644 artiq/test/lit/embedding/syscall_arg_attrs.py delete mode 100644 artiq/test/lit/try_loop/try_finally_while_try_finally_break.py delete mode 100644 artiq/test/lit/try_loop/try_finally_while_try_reraise.py delete mode 100644 artiq/test/lit/try_loop/try_finally_while_try_return.py diff --git a/artiq/test/lit/embedding/syscall_arg_attrs.py b/artiq/test/lit/embedding/syscall_arg_attrs.py deleted file mode 100644 index 67207dc32..000000000 --- a/artiq/test/lit/embedding/syscall_arg_attrs.py +++ /dev/null @@ -1,30 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -# Make sure `byval` and `sret` are specified both at the call site and the -# declaration. This isn't caught by the LLVM IR validator, but mismatches -# lead to miscompilations (at least in LLVM 11). - - -@kernel -def entrypoint(): - # CHECK: call void @accept_str\({ i8\*, i32 }\* nonnull byval - accept_str("foo") - - # CHECK: call void @return_str\({ i8\*, i32 }\* nonnull sret - return_str() - - -# CHECK: declare void @accept_str\({ i8\*, i32 }\* byval\) -@syscall -def accept_str(name: TStr) -> TNone: - pass - - -# CHECK: declare void @return_str\({ i8\*, i32 }\* sret\) -@syscall -def return_str() -> TStr: - pass diff --git a/artiq/test/lit/try_loop/try_finally_while_try_finally_break.py b/artiq/test/lit/try_loop/try_finally_while_try_finally_break.py deleted file mode 100644 index c66d88ceb..000000000 --- a/artiq/test/lit/try_loop/try_finally_while_try_finally_break.py +++ /dev/null @@ -1,42 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def run(): - loop = 0 - print("start") - try: - while True: - print("loop") - try: - if loop == 0: - loop += 1 - continue - func() - break - except RuntimeError: - print("except") - return False - finally: - print("finally2") - print("after-while") - finally: - print("finally1") - print("exit") - return True - - -def func(): - print("func") - -# CHECK-L: start -# CHECK-NEXT-L: loop -# CHECK-NEXT-L: finally2 -# CHECK-NEXT-L: loop -# CHECK-NEXT-L: func -# CHECK-NEXT-L: finally2 -# CHECK-NEXT-L: after-while -# CHECK-NEXT-L: finally1 -# CHECK-NEXT-L: exit - -run() diff --git a/artiq/test/lit/try_loop/try_finally_while_try_reraise.py b/artiq/test/lit/try_loop/try_finally_while_try_reraise.py deleted file mode 100644 index f7c6db84f..000000000 --- a/artiq/test/lit/try_loop/try_finally_while_try_reraise.py +++ /dev/null @@ -1,42 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def run(): - print("start") - try: - try: - while True: - print("loop") - try: - print("try") - func() - print("unreachable") - return True - except RuntimeError: - print("except1") - raise - print("unreachable") - finally: - print("finally1") - print("unreachable") - return False - except RuntimeError: - print("except2") - raise - finally: - print("finally2") - return True - - -def func(): - raise RuntimeError("Test") - -# CHECK-L: start -# CHECK-NEXT-L: loop -# CHECK-NEXT-L: try -# CHECK-NEXT-L: except1 -# CHECK-NEXT-L: finally1 -# CHECK-NEXT-L: except2 -# CHECK-NEXT-L: finally2 -run() diff --git a/artiq/test/lit/try_loop/try_finally_while_try_return.py b/artiq/test/lit/try_loop/try_finally_while_try_return.py deleted file mode 100644 index 92a547f02..000000000 --- a/artiq/test/lit/try_loop/try_finally_while_try_return.py +++ /dev/null @@ -1,29 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def run(): - try: - while True: - try: - print("try") - func() - return True - except RuntimeError: - print("except") - return False - print("unreachable") - finally: - print("finally") - print("unreachable") - return False - - -def func(): - pass - -# CHECK-L: try -# CHECK-NOT-L: except -# CHECK-NOT-L: unreachable -# CHECK-L: finally -run() From b77f6886be2dbfaac7e41ae2044ccbc827ca527c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Jun 2022 22:55:34 +0800 Subject: [PATCH 207/352] test_i2c: port to NAC3 --- artiq/test/coredevice/test_i2c.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_i2c.py b/artiq/test/coredevice/test_i2c.py index e8293db9d..3282485f0 100644 --- a/artiq/test/coredevice/test_i2c.py +++ b/artiq/test/coredevice/test_i2c.py @@ -3,14 +3,23 @@ import os, unittest from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase from artiq.coredevice.exceptions import I2CError +from artiq.coredevice.core import Core from artiq.coredevice.i2c import I2CSwitch, i2c_read_byte +@nac3 class I2CSwitchTest(EnvExperiment): + core: KernelInvariant[Core] + i2c_switch: KernelInvariant[I2CSwitch] + def build(self): self.setattr_device("core") self.setattr_device("i2c_switch") + @rpc + def set_passed(self, passed: bool): + self.set_dataset("passed", passed) + @kernel def run(self): passed = True @@ -20,10 +29,14 @@ class I2CSwitchTest(EnvExperiment): # otherwise we cannot guarantee exact readback values if i2c_read_byte(self.i2c_switch.busno, self.i2c_switch.address) != 1 << i: passed = False - self.set_dataset("passed", passed) + self.set_passed(passed) +@nac3 class NonexistentI2CBus(EnvExperiment): + core: KernelInvariant[Core] + broken_switch: KernelInvariant[I2CSwitch] + def build(self): self.setattr_device("core") self.setattr_device("i2c_switch") # HACK: only run this test on boards with I2C From ba30705fa5778a9621e22b28b44010c3e8dd18df Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Jun 2022 23:13:46 +0800 Subject: [PATCH 208/352] core: allow re-creation of Core object, do not use _allow_registration global variable --- artiq/coredevice/core.py | 5 +++-- artiq/language/core.py | 3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 55aa598ee..199d02b25 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -56,15 +56,16 @@ class Core: self.core = self self.comm.core = self self.target = target + self.analyzed = False self.compiler = nac3artiq.NAC3(target) def close(self): self.comm.close() def compile(self, method, args, kwargs, embedding_map, file_output=None): - if core_language._allow_registration: + if not self.analyzed: self.compiler.analyze(core_language._registered_functions, core_language._registered_classes) - core_language._allow_registration = False + self.analyzed = True if hasattr(method, "__self__"): obj = method.__self__ diff --git a/artiq/language/core.py b/artiq/language/core.py index cb1908d26..379f57aaa 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -46,18 +46,15 @@ def ceil64(x): return ceil(x) -_allow_registration = True # Delay NAC3 analysis until all referenced variables are supposed to exist on the CPython side. _registered_functions = set() _registered_classes = set() def _register_function(fun): - assert _allow_registration import_cache.add_module_to_cache(getmodule(fun)) _registered_functions.add(fun) def _register_class(cls): - assert _allow_registration import_cache.add_module_to_cache(getmodule(cls)) _registered_classes.add(cls) From dc006b1a40e03f6a02aac056bdf0fa70e370e12b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Jun 2022 23:36:27 +0800 Subject: [PATCH 209/352] test_analyzer: port to NAC3 --- artiq/test/coredevice/test_analyzer.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/artiq/test/coredevice/test_analyzer.py b/artiq/test/coredevice/test_analyzer.py index cf8a64540..67f5a8bc8 100644 --- a/artiq/test/coredevice/test_analyzer.py +++ b/artiq/test/coredevice/test_analyzer.py @@ -1,11 +1,22 @@ +import unittest + +from numpy import int64 + from artiq.experiment import * from artiq.coredevice.comm_analyzer import (decode_dump, StoppedMessage, OutputMessage, InputMessage, _extract_log_chars, get_analyzer_dump) +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut, TTLInOut from artiq.test.hardware_testbench import ExperimentCase +@nac3 class CreateTTLPulse(EnvExperiment): + core: KernelInvariant[Core] + loop_in: KernelInvariant[TTLInOut] + loop_out: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("loop_in") @@ -16,7 +27,7 @@ class CreateTTLPulse(EnvExperiment): self.core.reset() self.loop_in.input() self.loop_out.output() - delay(1*us) + self.core.delay(1.*us) self.loop_out.off() @kernel @@ -24,22 +35,26 @@ class CreateTTLPulse(EnvExperiment): self.core.break_realtime() with parallel: with sequential: - delay_mu(100) - self.loop_out.pulse_mu(1000) - self.loop_in.count(self.loop_in.gate_both_mu(1200)) + delay_mu(int64(100)) + self.loop_out.pulse_mu(int64(1000)) + self.loop_in.count(self.loop_in.gate_both_mu(int64(1200))) +@nac3 class WriteLog(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") @kernel def run(self): self.core.reset() - rtio_log("foo", 32) + # NAC3TODO rtio_log("foo", 32) class AnalyzerTest(ExperimentCase): + @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/298") def test_ttl_pulse(self): core_host = self.device_mgr.get_desc("core")["arguments"]["host"] @@ -65,6 +80,7 @@ class AnalyzerTest(ExperimentCase): abs(input_messages[0].timestamp - input_messages[1].timestamp), 1000, delta=4) + @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/297") def test_rtio_log(self): core_host = self.device_mgr.get_desc("core")["arguments"]["host"] From cc3d86ff1231db71952686887ea8cc2c875cbd3b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Jun 2022 23:43:43 +0800 Subject: [PATCH 210/352] test_cache: port to NAC3 --- artiq/test/coredevice/test_cache.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/artiq/test/coredevice/test_cache.py b/artiq/test/coredevice/test_cache.py index 5fc94e4ed..10d586e02 100644 --- a/artiq/test/coredevice/test_cache.py +++ b/artiq/test/coredevice/test_cache.py @@ -1,27 +1,38 @@ +import unittest + +from numpy import int32 + from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.cache import CoreCache from artiq.coredevice.exceptions import CacheError from artiq.test.hardware_testbench import ExperimentCase +@nac3 class _Cache(EnvExperiment): + core: KernelInvariant[Core] + core_cache: KernelInvariant[CoreCache] + def build(self): self.setattr_device("core") self.setattr_device("core_cache") @kernel - def get(self, key): + def get(self, key: str) -> list[int32]: return self.core_cache.get(key) @kernel - def put(self, key, value): + def put(self, key: str, value: list[int32]): self.core_cache.put(key, value) @kernel - def get_put(self, key, value): + def get_put(self, key: str, value: list[int32]): self.get(key) self.put(key, value) +@unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/299") class CacheTest(ExperimentCase): def test_get_empty(self): exp = self.create(_Cache) From d15d922236bf037ae9858be25b0087acd2b24860 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Jun 2022 23:56:14 +0800 Subject: [PATCH 211/352] test_compile: port to NAC3 --- artiq/test/coredevice/test_compile.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/artiq/test/coredevice/test_compile.py b/artiq/test/coredevice/test_compile.py index 060cd1b8f..0213ef0cf 100644 --- a/artiq/test/coredevice/test_compile.py +++ b/artiq/test/coredevice/test_compile.py @@ -3,6 +3,8 @@ import sys import subprocess import unittest import tempfile + +from artiq.coredevice.core import Core from artiq.coredevice.comm_mgmt import CommMgmt from artiq.test.hardware_testbench import ExperimentCase from artiq.experiment import * @@ -11,7 +13,16 @@ from artiq.experiment import * artiq_root = os.getenv("ARTIQ_ROOT") +# NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/297 +@extern +def core_log(s: str): + ... + + +@nac3 class CheckLog(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") @@ -20,6 +31,7 @@ class CheckLog(EnvExperiment): core_log("test_artiq_compile") +@unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/300") class TestCompile(ExperimentCase): def test_compile(self): core_addr = self.device_mgr.get_desc("core")["arguments"]["host"] From 85693e45e72d13355c182dfc81647399da12b553 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Jun 2022 23:57:01 +0800 Subject: [PATCH 212/352] fix coredevice comm serve --- artiq/coredevice/comm_kernel.py | 2 +- artiq/frontend/artiq_run.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index c89b874f1..1e7febd0d 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -168,7 +168,7 @@ class CommKernelDummy: def run(self): pass - def serve(self, embedding_map, symbolizer, demangler): + def serve(self, embedding_map, symbolizer): pass def check_system_info(self): diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index e8c6d86e8..89578ec9b 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -33,7 +33,7 @@ class FileRunner(EnvExperiment): self.core.comm.load(kernel_library) self.core.comm.run() - self.core.comm.serve(None, None, None) + self.core.comm.serve(None, None) class ELFRunner(FileRunner): From 8e206e92f538139a10fd668321b66c122a6ed7d0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 7 Jun 2022 00:15:51 +0800 Subject: [PATCH 213/352] test_pulse_rate: port to NAC3 --- artiq/test/coredevice/test_rtio.py | 35 ++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 20a8d0ed6..6c9969399 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -9,6 +9,8 @@ from math import sqrt from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase from artiq.coredevice import exceptions +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut from artiq.coredevice.comm_mgmt import CommMgmt from artiq.coredevice.comm_analyzer import (StoppedMessage, OutputMessage, InputMessage, decode_dump, get_analyzer_dump) @@ -118,27 +120,36 @@ class ClockGeneratorLoopback(EnvExperiment): self.set_dataset("count", self.loop_clock_in.count(now_mu())) +@nac3 class PulseRate(EnvExperiment): + core: KernelInvariant[Core] + ttl_out: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("ttl_out") + @rpc + def set_pulse_rate(self, pulse_rate: float): + self.set_dataset("pulse_rate", pulse_rate) + @kernel def run(self): self.core.reset() - dt = self.core.seconds_to_mu(300*ns) - while True: - for i in range(10000): - try: - self.ttl_out.pulse_mu(dt) - delay_mu(dt) - except RTIOUnderflow: - dt += 1 - self.core.break_realtime() - break + dt = self.core.seconds_to_mu(300.*ns) + i = 10000 + while i > 0: + try: + self.ttl_out.pulse_mu(dt) + delay_mu(dt) + except RTIOUnderflow: + dt += int64(1) + i = 10000 + self.core.break_realtime() else: - self.set_dataset("pulse_rate", self.core.mu_to_seconds(dt)) - return + i -= 1 + self.set_pulse_rate(self.core.mu_to_seconds(dt)) + class PulseRateAD9914DDS(EnvExperiment): From 5261375301aea08d2f32e564b430bcd3c29ef3b7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 2 Jul 2022 19:19:07 +0800 Subject: [PATCH 214/352] update dependencies --- flake.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/flake.lock b/flake.lock index 3c1693632..6eed888fc 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1654510461, - "narHash": "sha256-YWtJOQ5XsJGWBX1AihD03a+m/OHtG2bdhjFmx18NdRY=", + "lastModified": 1656759859, + "narHash": "sha256-TIXcMtuNKkBWyL0+foFsLjwTCpgjWyODwOu3p/3fdno=", "ref": "master", - "rev": "8e6e4d6715bdfa4a5639068e4a78e89b714fb8d7", - "revCount": 787, + "rev": "b24246354864de7895fd0d183e11c0923343acc7", + "revCount": 788, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,11 +60,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1654360807, - "narHash": "sha256-wYG86PUkPZ1P/oHsCpepTkb/U26poaEPPp1XFjRsgdA=", + "lastModified": 1656589841, + "narHash": "sha256-Kqd6r9aNIzjYGhMFYATdKwRbXBCGLcdqAJMLr4I8LG0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d9794b04bffb468b886c553557489977ae5f4c65", + "rev": "dbb62c34bbb5cdf05f1aeab07638b24b0824d605", "type": "github" }, "original": { @@ -92,11 +92,11 @@ ] }, "locked": { - "lastModified": 1654009659, - "narHash": "sha256-/X4gbvqbth0B8lYFZNp1WyJ18N3uJakjLGuWTkRPLMQ=", + "lastModified": 1654830914, + "narHash": "sha256-tratXcWu6Dgzd0Qd9V6EMjuNlE9qDN1pKFhP+Gt0b64=", "owner": "m-labs", "repo": "sipyco", - "rev": "d2359ebf43e5283b44d7d40c76382463be4b76f6", + "rev": "58b0935f7ae47659abee5b5792fa594153328d6f", "type": "github" }, "original": { @@ -108,11 +108,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1650337393, - "narHash": "sha256-rm1SlFmF2ASz0vIy2nDEzGlyRw2oYNeJRr8Kh8Mg2Qc=", + "lastModified": 1656649178, + "narHash": "sha256-A91sZRrprEuPOtIUVxm6wX5djac9wnNZQ4+cU1nvJPc=", "owner": "m-labs", "repo": "migen", - "rev": "d4e3f34177c32f09904397179e6ed9c83175e528", + "rev": "0fb91737090fe45fd764ea3f71257a4c53c7a4ae", "type": "github" }, "original": { From 65300bcf929149ef3f681b86230f4c2425baee65 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 4 Jul 2022 18:08:56 +0800 Subject: [PATCH 215/352] flake: update dependencies --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 6eed888fc..f4f8ed797 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1656759859, - "narHash": "sha256-TIXcMtuNKkBWyL0+foFsLjwTCpgjWyODwOu3p/3fdno=", + "lastModified": 1656929196, + "narHash": "sha256-EUkwsjl4dtRVog7tL6AOIVUUlJws5TIKHOnEj73aeHg=", "ref": "master", - "rev": "b24246354864de7895fd0d183e11c0923343acc7", - "revCount": 788, + "rev": "96b3a3bf5c65e514de0cf230e07da84258edd486", + "revCount": 790, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From cc3eda8e9107f982e087649463284453b26194b5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 5 Aug 2022 22:08:31 +0800 Subject: [PATCH 216/352] flake: update dependencies --- flake.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/flake.lock b/flake.lock index f4f8ed797..fbb0e9649 100644 --- a/flake.lock +++ b/flake.lock @@ -27,11 +27,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1650459918, - "narHash": "sha256-sroCK+QJTmoXtcRkwZyKOP9iAYOPID2Bwdxn4GkG16w=", + "lastModified": 1657214286, + "narHash": "sha256-rO/4oymKXU09wG2bcTt4uthPCp1XsBZjxuCJo3yVXNs=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "e1f7540fc0a8b989fb8cf701dc4fd7fc76bcf168", + "rev": "0508a66e28a5792fdfb126bbf4dec1029c2509e0", "type": "github" }, "original": { @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1656929196, - "narHash": "sha256-EUkwsjl4dtRVog7tL6AOIVUUlJws5TIKHOnEj73aeHg=", + "lastModified": 1659695040, + "narHash": "sha256-vJG1IsDJ1KMbAf9jEIwsVsC6NDiGYst4/o4k9xPBqaI=", "ref": "master", - "rev": "96b3a3bf5c65e514de0cf230e07da84258edd486", - "revCount": 790, + "rev": "fff4b651697263f403f5270d09c08797572a3719", + "revCount": 797, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -60,16 +60,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1656589841, - "narHash": "sha256-Kqd6r9aNIzjYGhMFYATdKwRbXBCGLcdqAJMLr4I8LG0=", + "lastModified": 1659689094, + "narHash": "sha256-cXrWxpPYpV1PeEhtpQf9W++8aCgwzxpx2PzfszPofJE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "dbb62c34bbb5cdf05f1aeab07638b24b0824d605", + "rev": "697fc6ae98d077f6448cada3ecd63465c48c6af5", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-22.05", + "ref": "master", "repo": "nixpkgs", "type": "github" } From d180af1debd247e4f8760fec9f6559933ff393e4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 5 Aug 2022 22:11:05 +0800 Subject: [PATCH 217/352] flake: bump major version --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 3bd832db8..0ec190617 100644 --- a/flake.nix +++ b/flake.nix @@ -16,7 +16,7 @@ let pkgs = import nac3.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; }; - artiqVersionMajor = 8; + artiqVersionMajor = 9; artiqVersionMinor = self.sourceInfo.revCount or 0; artiqVersionId = self.sourceInfo.shortRev or "unknown"; artiqVersion = (builtins.toString artiqVersionMajor) + "." + (builtins.toString artiqVersionMinor) + "." + artiqVersionId + ".beta"; From 5ebccc2378d8b2c285ad2d5f434733882da063fd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 5 Aug 2022 22:28:07 +0800 Subject: [PATCH 218/352] flake: disable failing sphinx-argparse tests --- flake.nix | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/flake.nix b/flake.nix index 0ec190617..9cf0d036a 100644 --- a/flake.nix +++ b/flake.nix @@ -267,6 +267,21 @@ paths = [ openocd-fixed bscan_spi_bitstreams-pkg ]; }; + # https://github.com/ashb/sphinx-argparse/issues/5 + sphinx-argparse = pkgs.python3Packages.buildPythonPackage rec { + pname = "sphinx-argparse"; + version = "0.3.1"; + src = pkgs.python3Packages.fetchPypi { + inherit pname version; + sha256 = "82151cbd43ccec94a1530155f4ad34f251aaca6a0ffd5516d7fadf952d32dc1e"; + }; + checkInputs = [ pkgs.python3Packages.pytest ]; + checkPhase = + '' + pytest -vv -k "not test_parse_nested and not test_parse_nested_with_alias and not test_parse_groups and not test_action_groups_with_subcommands" + ''; + propagatedBuildInputs = [ pkgs.python3Packages.sphinx ]; + }; sphinxcontrib-wavedrom = pkgs.python3Packages.buildPythonPackage rec { pname = "sphinxcontrib-wavedrom"; version = "3.0.2"; @@ -292,14 +307,14 @@ target = "kc705"; variant = "nist_clock"; }; - inherit sphinxcontrib-wavedrom latex-artiq-manual; + inherit sphinx-argparse sphinxcontrib-wavedrom latex-artiq-manual; artiq-manual-html = pkgs.stdenvNoCC.mkDerivation rec { name = "artiq-manual-html-${version}"; version = artiqVersion; src = self; buildInputs = [ pkgs.python3Packages.sphinx pkgs.python3Packages.sphinx_rtd_theme - pkgs.python3Packages.sphinx-argparse sphinxcontrib-wavedrom + sphinx-argparse sphinxcontrib-wavedrom ]; buildPhase = '' export VERSIONEER_OVERRIDE=${artiqVersion} @@ -319,7 +334,7 @@ src = self; buildInputs = [ pkgs.python3Packages.sphinx pkgs.python3Packages.sphinx_rtd_theme - pkgs.python3Packages.sphinx-argparse sphinxcontrib-wavedrom + sphinx-argparse sphinxcontrib-wavedrom latex-artiq-manual ]; buildPhase = '' @@ -358,7 +373,7 @@ packages.x86_64-linux.vivado packages.x86_64-linux.openocd-bscanspi pkgs.python3Packages.sphinx pkgs.python3Packages.sphinx_rtd_theme - pkgs.python3Packages.sphinx-argparse sphinxcontrib-wavedrom latex-artiq-manual + sphinx-argparse sphinxcontrib-wavedrom latex-artiq-manual ]; }; From afd4f369d038d36ca5c9f70509ab1aa4087ded26 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 5 Aug 2022 22:44:09 +0800 Subject: [PATCH 219/352] windows: fix python module installation paths --- flake.lock | 8 ++++---- windows/PKGBUILD.common | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index fbb0e9649..07238c01f 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1659695040, - "narHash": "sha256-vJG1IsDJ1KMbAf9jEIwsVsC6NDiGYst4/o4k9xPBqaI=", + "lastModified": 1659710552, + "narHash": "sha256-BFM0wnEaWFBHwHNET2KZBB0LxKGA44asnDBnMXQ6KMA=", "ref": "master", - "rev": "fff4b651697263f403f5270d09c08797572a3719", - "revCount": 797, + "rev": "813bfa92a7b56fa5fe8d11bac4c224b84903e7c0", + "revCount": 798, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, diff --git a/windows/PKGBUILD.common b/windows/PKGBUILD.common index e5d8e2a74..504785679 100644 --- a/windows/PKGBUILD.common +++ b/windows/PKGBUILD.common @@ -7,7 +7,7 @@ sha256sums=("SKIP") build() { mkdir mingw64 - export PYTHONPATH=`pwd`/mingw64/lib/python3.9/site-packages + export PYTHONPATH=`pwd`/mingw64/lib/python3.10/site-packages chmod +w -R source cd source wine-msys2-build python setup.py install --single-version-externally-managed --prefix=../mingw64 --record=setuptools-sucks.txt @@ -15,7 +15,7 @@ build() { # setuptools creates this file if it doesn't already exist, which causes conflicts between pacman packages # see: https://corte.si/posts/code/setuptoolssucks/ - rm -f mingw64/lib/python3.9/site-packages/easy-install.pth + rm -f mingw64/lib/python3.10/site-packages/easy-install.pth # patch broken shebangs (Z:/nix/store/...) for entrypoint in mingw64/bin/*-script.py; do [ -f "$entrypoint" ] || continue From a2d0ebabfe9ddd75fabe6b1037a5d0b23ef0124e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 5 Aug 2022 22:57:32 +0800 Subject: [PATCH 220/352] phaser: avoid OverflowError --- artiq/coredevice/phaser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index e26a3fafe..f56ff5187 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -1,5 +1,5 @@ from __future__ import annotations -from numpy import int32, int64 +from numpy import uint32, int32, int64 from artiq.language.core import * from artiq.coredevice.core import Core @@ -178,7 +178,7 @@ class Phaser: self.sync_dly = sync_dly self.dac_mmap = DAC34H84(dac).get_mmap() - self.dac_mmap = [int32(x) for x in self.dac_mmap] # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/14 + self.dac_mmap = [int32(uint32(x)) for x in self.dac_mmap] # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/14 self.channel = [PhaserChannel(self, ch, trf) for ch, trf in enumerate([trf0, trf1])] From c1d865c107187b64f55bf3c1938a103846623e3a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 5 Aug 2022 22:59:47 +0800 Subject: [PATCH 221/352] phaser: avoid OverflowError (2) --- artiq/coredevice/phaser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index f56ff5187..dd22b6449 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -797,7 +797,7 @@ class PhaserChannel: self.phaser = phaser self.index = index self.trf_mmap = TRF372017(trf).get_mmap() - self.trf_mmap = [int32(x) for x in self.trf_mmap] # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/14 + self.trf_mmap = [int32(uint32(x)) for x in self.trf_mmap] # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/14 self.oscillator = [PhaserOscillator(self, osc) for osc in range(5)] From e6067a218bf00277c6536210f1491edd51381a8b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 18 Aug 2022 14:35:23 +0800 Subject: [PATCH 222/352] versioneer: fix default --- versioneer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versioneer.py b/versioneer.py index f6393d21e..ca4e6276f 100644 --- a/versioneer.py +++ b/versioneer.py @@ -11,7 +11,7 @@ def get_rev(): """ def get_version(): - return os.getenv("VERSIONEER_OVERRIDE", default="8.0.beta") + return os.getenv("VERSIONEER_OVERRIDE", default="9.0.beta") def get_rev(): return os.getenv("VERSIONEER_REV", default="unknown") From c8f76e389914cf2d695e40ed5217cd34e16d872a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 18 Aug 2022 14:37:51 +0800 Subject: [PATCH 223/352] flake: reenable tests --- flake.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/flake.nix b/flake.nix index 2e6211d6d..677e4b619 100644 --- a/flake.nix +++ b/flake.nix @@ -77,7 +77,6 @@ pname = "artiq"; version = artiqVersion; src = self; - doCheck = false; preBuild = '' From ece1269c2abf160ef6390857df04cc2bc782fd91 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 Nov 2022 18:11:48 +0800 Subject: [PATCH 224/352] flake: fix libcrypt.so.1 not found by vivado --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index 75a1b50cf..225b8419a 100644 --- a/flake.nix +++ b/flake.nix @@ -43,6 +43,7 @@ }); vivadoDeps = pkgs: with pkgs; [ + libxcrypt ncurses5 zlib libuuid From 66daf3368ec7098de009d72e11b7c1b2f83db41c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 Nov 2022 18:12:20 +0800 Subject: [PATCH 225/352] flake: remove libartiq-support leftover --- flake.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/flake.nix b/flake.nix index 225b8419a..77f657814 100644 --- a/flake.nix +++ b/flake.nix @@ -384,7 +384,6 @@ sphinx-argparse sphinxcontrib-wavedrom latex-artiq-manual ]; shellHook = '' - export LIBARTIQ_SUPPORT=`libartiq-support` export QT_PLUGIN_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.dev.qtPluginPrefix} export QML2_IMPORT_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.dev.qtQmlPrefix} ''; From f930b86dbeeffd697d56ccc123bea33b45d6ad91 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 Nov 2022 18:12:38 +0800 Subject: [PATCH 226/352] flake: cleanup --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 77f657814..3009b3374 100644 --- a/flake.nix +++ b/flake.nix @@ -384,7 +384,7 @@ sphinx-argparse sphinxcontrib-wavedrom latex-artiq-manual ]; shellHook = '' - export QT_PLUGIN_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.dev.qtPluginPrefix} + export QT_PLUGIN_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.dev.qtPluginPrefix} export QML2_IMPORT_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.dev.qtQmlPrefix} ''; }; From 844193148a27b23da5ff760398a6e9d3b0e40d81 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 Nov 2022 18:19:58 +0800 Subject: [PATCH 227/352] msys2: add qt5-svg dependency --- windows/PKGBUILD.artiq | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/PKGBUILD.artiq b/windows/PKGBUILD.artiq index 2a03ed575..640d88197 100644 --- a/windows/PKGBUILD.artiq +++ b/windows/PKGBUILD.artiq @@ -7,6 +7,7 @@ depends=( "mingw-w64-x86_64-python" "mingw-w64-x86_64-python-h5py" "mingw-w64-x86_64-python-pyqt5" + "mingw-w64-x86_64-qt5-svg" "mingw-w64-x86_64-python-qasync" "mingw-w64-x86_64-python-pyqtgraph" "mingw-w64-x86_64-python-numpy" From 287e55c08a58bcf36ca944cd7e86e1df55c87c61 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 15 Jan 2023 12:26:08 +0800 Subject: [PATCH 228/352] sampler: fix mistake in c591e7e3 --- artiq/coredevice/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/sampler.py b/artiq/coredevice/sampler.py index c0a7329ff..15372a7e1 100644 --- a/artiq/coredevice/sampler.py +++ b/artiq/coredevice/sampler.py @@ -164,4 +164,4 @@ class Sampler: for i in range(n): channel = i + 8 - len(data) gain = (self.gains >> (channel*2)) & 0b11 - data[i] = adc_mu_to_volt(adc_data[i], gain, self.revision) + data[i] = adc_mu_to_volt(adc_data[i], gain, self.corrected_fs) From 9e8167e1fac61aa6effb7d8ed31ce7f7168eac63 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 15 Jan 2023 12:26:52 +0800 Subject: [PATCH 229/352] artiq_ddb_template: fix mistake in 18524911 --- artiq/frontend/artiq_ddb_template.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index bc3d25900..3c6491739 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -539,10 +539,10 @@ class PeripheralManager: def process_phaser(self, rtio_offset, peripheral): mode = peripheral.get("mode", "base") if mode == "miqro": - dac = f', "dac": {{"pll_m": 16, "pll_n": 3, "interpolation": 2}}, "gw_rev"={PHASER_GW_MIQRO}' + dac = f', "dac": {{"pll_m": 16, "pll_n": 3, "interpolation": 2}}, "gw_rev": {PHASER_GW_MIQRO}' n_channels = 3 else: - dac = f', "gw_rev"={PHASER_GW_BASE}' + dac = f', "gw_rev": {PHASER_GW_BASE}' n_channels = 5 self.gen(""" device_db["{name}"] = {{ From 78daace19a42537ce3648a7640f5d913a5c011ea Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 15 Jan 2023 12:30:08 +0800 Subject: [PATCH 230/352] ad9910: fix pll_en doc --- artiq/coredevice/ad9910.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 3d6f882c5..e2600d6ac 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -127,7 +127,7 @@ class AD9910: f_ref/clk_div*pll_n where f_ref is the reference frequency and clk_div is the reference clock divider (both set in the parent Urukul CPLD instance). - :param pll_en: PLL enable bit, set to 0 to bypass PLL (default: 1). + :param pll_en: PLL enable bit, set to False to bypass PLL (default: True). Note that when bypassing the PLL the red front panel LED may remain on. :param pll_cp: DDS PLL charge pump setting. :param pll_vco: DDS PLL VCO range selection. From 3bfd743c47ae7d3aefb46a17363c890ec112f6b3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Mar 2023 18:24:33 +0800 Subject: [PATCH 231/352] flake: update dependencies --- flake.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/flake.lock b/flake.lock index 0e9cd2eaf..fa6ad5de0 100644 --- a/flake.lock +++ b/flake.lock @@ -43,11 +43,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1672878308, - "narHash": "sha256-0+fl6PHokhtSV+w58z2QD2rTf8QhcOGsT9o4LwHHZHE=", + "lastModified": 1677493379, + "narHash": "sha256-A1gO8zlWLv3+tZ3cGVB1WYvvoN9pbFyv0xIJHcTsckw=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "d38863db88e100866b3e494a651ee4962b762fcc", + "rev": "78e723925daf5c9e8d0a1837ec27059e61649cb6", "type": "github" }, "original": { @@ -61,11 +61,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1673683761, - "narHash": "sha256-mvYqz1ZNGwVwB9cFe1yoMNSYm8qr5FN2baqCFYXfxh4=", + "lastModified": 1678259949, + "narHash": "sha256-rHJoF7kS5HLuD2hIYATpAZ9qi5zXwLtl7hPwgHGv4oo=", "ref": "refs/heads/master", - "rev": "c269444c0bbfadb0fae662cc4a3b4582a9362dbc", - "revCount": 805, + "rev": "aead36f0fd17f69d6e6e33215430805b1ffcb917", + "revCount": 806, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -76,11 +76,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1673345971, - "narHash": "sha256-4DfFcKLRfVUTyuGrGNNmw37IeIZSoku9tgTVmu/iD98=", + "lastModified": 1678137616, + "narHash": "sha256-T+lWTRdcYaOnZQW+Ehdlg+YldC2l9cq2GXJFPq22Nxc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "54644f409ab471e87014bb305eac8c50190bcf48", + "rev": "7edcdf7b169c33cd3eef9aba50521ce93ee666b8", "type": "github" }, "original": { @@ -124,11 +124,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1673433200, - "narHash": "sha256-ribBG06gsucz5oBS+O6aL8s2oJjx+qfl+vXmspts8gg=", + "lastModified": 1674045327, + "narHash": "sha256-oYdeY0MbTReKbAwmSznnqw0wNawdInJoFJVWW3tesFA=", "owner": "m-labs", "repo": "migen", - "rev": "f3e9145c9825514a1b4225378936569da4df8e12", + "rev": "ccaee68e14d3636e1d8fb2e0864dd89b1b1f7384", "type": "github" }, "original": { From 825c49a9110bf2f7828339518f02631673d8fe8d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 30 Apr 2023 16:43:52 +0800 Subject: [PATCH 232/352] artiq_ddb_template: fix pll_en typing --- artiq/coredevice/coredevice_generic.schema.json | 12 ++++-------- artiq/frontend/artiq_ddb_template.py | 6 +++--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/artiq/coredevice/coredevice_generic.schema.json b/artiq/coredevice/coredevice_generic.schema.json index e11ba4976..c7e74c68e 100644 --- a/artiq/coredevice/coredevice_generic.schema.json +++ b/artiq/coredevice/coredevice_generic.schema.json @@ -303,10 +303,8 @@ "type": "integer" }, "pll_en": { - "type": "integer", - "minimum": 0, - "maximum": 1, - "default": 1 + "type": "boolean", + "default": true }, "pll_vco": { "type": "integer" @@ -372,10 +370,8 @@ "default": 32 }, "pll_en": { - "type": "integer", - "minimum": 0, - "maximum": 1, - "default": 1 + "type": "boolean", + "default": true }, "pll_vco": { "type": "integer" diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index ab9762814..9322e7f50 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -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.get("pll_en", True), 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.get("pll_en", True)) else: raise ValueError return next(channel) @@ -475,7 +475,7 @@ class PeripheralManager: refclk=peripheral.get("refclk", self.master_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.get("pll_en", True)) return next(channel) def process_zotino(self, rtio_offset, peripheral): From 5d2b3dafe37998fd7bca62251018d91d40e7d71b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 30 Apr 2023 16:46:35 +0800 Subject: [PATCH 233/352] remove lit from gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 77178c15e..78cd628d0 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ __pycache__/ /dist /*.egg-info /.coverage -/artiq/test/lit/*/Output/ /artiq/binaries /artiq/firmware/target/ /misoc_*/ From 730a00d2105fbbfddabd21a1c2fb0104573fb517 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 30 Apr 2023 16:53:14 +0800 Subject: [PATCH 234/352] flake: update dependencies --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index fa6ad5de0..e50e184d1 100644 --- a/flake.lock +++ b/flake.lock @@ -108,11 +108,11 @@ ] }, "locked": { - "lastModified": 1673433867, - "narHash": "sha256-a7Oq35YoDzPtISbqAsaT+2/v15HZ7G1q0ukXmKWdb7Q=", + "lastModified": 1681290481, + "narHash": "sha256-VEZcGhbtJGonRrrWi31evNDVSerlLjEPL0MZGm9VlB8=", "owner": "m-labs", "repo": "sipyco", - "rev": "38f8f4185d7db6b68bd7f71546da9077b1e2561c", + "rev": "727631ada6e59dc6ef0ad50bfcc376d2ffe805aa", "type": "github" }, "original": { @@ -140,11 +140,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1671158014, - "narHash": "sha256-50w0K2E2ympYrG1Tte/HVbsp4FS2U+yohqZByXTOo4I=", + "lastModified": 1679903508, + "narHash": "sha256-TI0agjSSMJtH4mgAMpSO128zxcwSo/AjY1B6AW7zBQQ=", "ref": "refs/heads/master", - "rev": "26f039f9f6931a20a04ccd0f0a5402f67f553916", - "revCount": 2436, + "rev": "0cf0ebb7d4f56cc6d44a3dea3e386efab9d82419", + "revCount": 2437, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From c13903802224e0c73c62b084adfcd87ead4597a2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 30 Apr 2023 17:17:39 +0800 Subject: [PATCH 235/352] flake: update dependencies --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index e50e184d1..d5ec2236c 100644 --- a/flake.lock +++ b/flake.lock @@ -61,11 +61,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1678259949, - "narHash": "sha256-rHJoF7kS5HLuD2hIYATpAZ9qi5zXwLtl7hPwgHGv4oo=", + "lastModified": 1682845907, + "narHash": "sha256-nQmDWeglDUVJH/Rhdg6uvE7Rdt8sEgC2J21Vs61BTDI=", "ref": "refs/heads/master", - "rev": "aead36f0fd17f69d6e6e33215430805b1ffcb917", - "revCount": 806, + "rev": "5b53be0311d67eedad5bec98b8abe2603e29850c", + "revCount": 807, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -76,11 +76,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1678137616, - "narHash": "sha256-T+lWTRdcYaOnZQW+Ehdlg+YldC2l9cq2GXJFPq22Nxc=", + "lastModified": 1682669017, + "narHash": "sha256-Vi+p4y3wnl0/4gcwTdmCO398kKlDaUrNROtf3GOD2NY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7edcdf7b169c33cd3eef9aba50521ce93ee666b8", + "rev": "7449971a3ecf857b4a554cf79b1d9dcc1a4647d8", "type": "github" }, "original": { From cc41b7085292e4d27d67d09770fa536791188ceb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 9 May 2023 13:13:51 +0800 Subject: [PATCH 236/352] msys2: add lmdb dependency --- windows/PKGBUILD.artiq | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/PKGBUILD.artiq b/windows/PKGBUILD.artiq index 640d88197..c2ae0b99f 100644 --- a/windows/PKGBUILD.artiq +++ b/windows/PKGBUILD.artiq @@ -6,6 +6,7 @@ license=("LGPL") depends=( "mingw-w64-x86_64-python" "mingw-w64-x86_64-python-h5py" + "mingw-w64-x86_64-python-lmdb" "mingw-w64-x86_64-python-pyqt5" "mingw-w64-x86_64-qt5-svg" "mingw-w64-x86_64-python-qasync" From 250d7e8f0fa7f70591625d19e0ce402e2ee97a38 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 9 May 2023 14:26:45 +0800 Subject: [PATCH 237/352] examples/nac3devices: add almazny --- artiq/examples/nac3devices/nac3devices.json | 5 +++-- artiq/examples/nac3devices/nac3devices.py | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json index ea70bc98f..7fda9ca78 100644 --- a/artiq/examples/nac3devices/nac3devices.json +++ b/artiq/examples/nac3devices/nac3devices.json @@ -1,8 +1,8 @@ { "target": "kasli", - "min_artiq_version": "8.0", + "min_artiq_version": "9.0", "variant": "nac3devices", - "hw_rev": "v1.1", + "hw_rev": "v2.0", "base": "standalone", "core_addr": "192.168.1.70", "peripherals": [ @@ -12,6 +12,7 @@ }, { "type": "mirny", + "almazny": true, "ports": [1], "clk_sel": "mmcx", "refclk": 125e6 diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index b64efe27b..1f2d54cc7 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -4,6 +4,7 @@ from artiq.coredevice.cache import CoreCache from artiq.coredevice.kasli_i2c import KasliEEPROM from artiq.coredevice.zotino import Zotino from artiq.coredevice.mirny import Mirny as MirnyCPLD +from artiq.coredevice.almazny import AlmaznyChannel from artiq.coredevice.adf5356 import ADF5356 from artiq.coredevice.urukul import CPLD as UrukulCPLD from artiq.coredevice.ad9912 import AD9912 @@ -22,6 +23,7 @@ class NAC3Devices(EnvExperiment): zotino0: KernelInvariant[Zotino] mirny0_cpld: KernelInvariant[MirnyCPLD] mirny0_ch0: KernelInvariant[ADF5356] + mirny0_almazny0: KernelInvariant[AlmaznyChannel] urukul0_cpld: KernelInvariant[UrukulCPLD] eeprom_urukul0: KernelInvariant[KasliEEPROM] urukul0_ch0: KernelInvariant[AD9912] @@ -39,6 +41,7 @@ class NAC3Devices(EnvExperiment): self.setattr_device("zotino0") self.setattr_device("mirny0_cpld") self.setattr_device("mirny0_ch0") + self.setattr_device("mirny0_almazny0") self.setattr_device("urukul0_cpld") self.setattr_device("eeprom_urukul0") self.setattr_device("urukul0_ch0") From 0edcd53c247a9a9ffb9e801e7f6394aa1d0eb135 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 9 May 2023 14:26:59 +0800 Subject: [PATCH 238/352] artiq_ddb_template: fix almazny --- artiq/frontend/artiq_ddb_template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 8cb24088e..9522c2f72 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -334,7 +334,7 @@ class PeripheralManager: "module": "artiq.coredevice.almazny", "class": "AlmaznyChannel", "arguments": {{ - "cpld_device": "{name}_cpld", + "host_mirny": "{name}_cpld", "channel": {i}, }}, }}""", From 4efb862280c7d09994a2fc1393bafe328c264d75 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 17 Jul 2023 15:54:39 +0800 Subject: [PATCH 239/352] flake: update dependencies --- flake.lock | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/flake.lock b/flake.lock index a60c79b2b..941e1c5fb 100644 --- a/flake.lock +++ b/flake.lock @@ -43,11 +43,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": { @@ -61,11 +61,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1685184981, - "narHash": "sha256-cl+mFQIUdxhlgetiGMkiSu1o9ffSwcni9592HV3uS1s=", + "lastModified": 1689303441, + "narHash": "sha256-LwlF+MOXrLsgA04164Q5EiBCGLFVOwkQAkSOGPuBLCs=", "ref": "refs/heads/master", - "rev": "b8d637f5c4340d12b747b7f1bfd1ef2b14540297", - "revCount": 809, + "rev": "283bd7c69ab5a6655437555f72eb8743f9741065", + "revCount": 812, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -76,11 +76,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1685004253, - "narHash": "sha256-AbVL1nN/TDicUQ5wXZ8xdLERxz/eJr7+o8lqkIOVuaE=", + "lastModified": 1688868408, + "narHash": "sha256-RR9N5XTAxSBhK8MCvLq9uxfdkd7etC//seVXldy0k48=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3e01645c40b92d29f3ae76344a6d654986a91a91", + "rev": "510d721ce097150ae3b80f84b04b13b039186571", "type": "github" }, "original": { @@ -108,11 +108,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": { @@ -140,11 +140,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 24d25206554eb2a069e91e50232854623b46b826 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Sep 2023 19:22:41 +0800 Subject: [PATCH 240/352] flake: update dependencies --- flake.lock | 72 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/flake.lock b/flake.lock index 941e1c5fb..b61ac294c 100644 --- a/flake.lock +++ b/flake.lock @@ -12,11 +12,11 @@ ] }, "locked": { - "lastModified": 1664405593, - "narHash": "sha256-yP441NerlLGig7n+9xHsx8yCtZ+Ggd0VqfBSzc20E04=", + "lastModified": 1693473687, + "narHash": "sha256-BdLddCWbvoEyakcGwhph9b5dIU1iA0hCQV7KYgU8nos=", "owner": "m-labs", "repo": "artiq-comtools", - "rev": "15ddac62813ef623a076ccf982b3bc63d314e651", + "rev": "f522ef3dbc65961f17b2d3d41e927409d970fd79", "type": "github" }, "original": { @@ -26,12 +26,15 @@ } }, "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1659877975, - "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "lastModified": 1692799911, + "narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=", "owner": "numtide", "repo": "flake-utils", - "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44", "type": "github" }, "original": { @@ -43,11 +46,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1687771476, - "narHash": "sha256-TSpqz6qYVRoqkEdOCawEQ4/cWt/4pracmvw17HK1tgE=", + "lastModified": 1690536331, + "narHash": "sha256-aRIf2FB2GTdfF7gl13WyETmiV/J7EhBGkSWXfZvlxcA=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "3a44b8783514e7d6db4b63df96071b6c2b014b07", + "rev": "db89c8707edcffefcd8e738459d511543a339ff5", "type": "github" }, "original": { @@ -61,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1689303441, - "narHash": "sha256-LwlF+MOXrLsgA04164Q5EiBCGLFVOwkQAkSOGPuBLCs=", + "lastModified": 1694603747, + "narHash": "sha256-syvFioLXiJZFnBl+W49gnc8MQzAd0/DiNzdZPZBa80Q=", "ref": "refs/heads/master", - "rev": "283bd7c69ab5a6655437555f72eb8743f9741065", - "revCount": 812, + "rev": "ff27e22ee6596760331a4dcc8aa412b6887109f4", + "revCount": 833, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -76,16 +79,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1688868408, - "narHash": "sha256-RR9N5XTAxSBhK8MCvLq9uxfdkd7etC//seVXldy0k48=", + "lastModified": 1694562957, + "narHash": "sha256-ZvDt5bxX6Ga+TQ6kvK5WEn7OQN87KAsMaRrFSdReIm8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "510d721ce097150ae3b80f84b04b13b039186571", + "rev": "f4a33546bdb5f81bd6cceb1b3cb19667145fed83", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.05", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } @@ -108,11 +111,11 @@ ] }, "locked": { - "lastModified": 1685540542, - "narHash": "sha256-wQJwL3xc6QVQbiJrt71/Z9tp4Eq1yqdGddcEiv7sPCw=", + "lastModified": 1693473454, + "narHash": "sha256-kr8Ur6JNW/xVRHdPn3ou980IAxg/n+f3ZQBHuJ1uaC4=", "owner": "m-labs", "repo": "sipyco", - "rev": "f5bf2ba875340a31a135aea14ad184575ca800ac", + "rev": "5467dcf9738673ab9a49e6f2377bda7c551b5f90", "type": "github" }, "original": { @@ -124,11 +127,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1674045327, - "narHash": "sha256-oYdeY0MbTReKbAwmSznnqw0wNawdInJoFJVWW3tesFA=", + "lastModified": 1693990700, + "narHash": "sha256-qJLA03QcZ5S9DrqrseuzIQBTWS7rjAbYJxLYZEQ8rxA=", "owner": "m-labs", "repo": "migen", - "rev": "ccaee68e14d3636e1d8fb2e0864dd89b1b1f7384", + "rev": "2cfee3e0db6fdca9b5918686ea77c93252e7cebd", "type": "github" }, "original": { @@ -140,11 +143,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1685415268, - "narHash": "sha256-g4+yeSV+HtWjcllM5wk4vNBUVCXtDOzUSKhxXPT7Fyc=", + "lastModified": 1693709836, + "narHash": "sha256-YiCk05RYLzZu1CYkQ2r7XtjwVEqkUGTQn388uOls9tI=", "ref": "refs/heads/master", - "rev": "6d48ce77b6746d3226a682790fbc95b90340986e", - "revCount": 2440, + "rev": "58dc4ee60d165ce9145cf3d904241fc154b6407f", + "revCount": 2448, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" @@ -154,6 +157,21 @@ "type": "git", "url": "https://github.com/m-labs/misoc.git" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", From 602b680b9da0da5fa1b49679cbb0acad1dd0b722 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Sep 2023 10:57:37 +0800 Subject: [PATCH 241/352] firmware: deal with rust nonsense Fixes "error: edition 2021 is unstable and only available with -Z unstable-options. error: could not compile `alloc`" --- flake.nix | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 5f6db7a66..8f5a21e3f 100644 --- a/flake.nix +++ b/flake.nix @@ -42,6 +42,10 @@ cargo = rust; }); + cargo-xbuild = pkgs.cargo-xbuild.overrideAttrs(oa: { + postPatch = "substituteInPlace src/sysroot.rs --replace 2021 2018"; + }); + vivadoDeps = pkgs: with pkgs; [ libxcrypt-legacy ncurses5 @@ -186,7 +190,7 @@ nativeBuildInputs = [ (pkgs.python3.withPackages(ps: [ migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ps.packaging ])) rust - pkgs.cargo-xbuild + cargo-xbuild pkgs.llvmPackages_14.clang-unwrapped pkgs.llvm_14 pkgs.lld_14 @@ -360,7 +364,7 @@ buildInputs = [ (packages.x86_64-linux.python3-mimalloc.withPackages(ps: with packages.x86_64-linux; [ migen misoc ps.paramiko microscope ps.packaging ] ++ artiq.propagatedBuildInputs)) rust - pkgs.cargo-xbuild + cargo-xbuild pkgs.llvmPackages_14.clang-unwrapped pkgs.llvm_14 pkgs.lld_14 @@ -383,7 +387,7 @@ buildInputs = [ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ps.packaging ])) rust - pkgs.cargo-xbuild + cargo-xbuild pkgs.llvmPackages_14.clang-unwrapped pkgs.llvm_14 pkgs.lld_14 From f89f775c91c4b334125731152891a74042cf3e5e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 5 Oct 2023 18:03:34 +0800 Subject: [PATCH 242/352] flake: update dependencies --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index b61ac294c..22377d044 100644 --- a/flake.lock +++ b/flake.lock @@ -46,11 +46,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1690536331, - "narHash": "sha256-aRIf2FB2GTdfF7gl13WyETmiV/J7EhBGkSWXfZvlxcA=", + "lastModified": 1695805681, + "narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "db89c8707edcffefcd8e738459d511543a339ff5", + "rev": "6eabade97bc28d707a8b9d82ad13ef143836736e", "type": "github" }, "original": { @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1694603747, - "narHash": "sha256-syvFioLXiJZFnBl+W49gnc8MQzAd0/DiNzdZPZBa80Q=", + "lastModified": 1696500173, + "narHash": "sha256-hOPpKVWSEIAhjnb7WQsnklIsj3PuVN2d1G0KfXdhxBw=", "ref": "refs/heads/master", - "rev": "ff27e22ee6596760331a4dcc8aa412b6887109f4", - "revCount": 833, + "rev": "901e921e00eb00c067a453b277329b36b7041891", + "revCount": 873, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,11 +79,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1694562957, - "narHash": "sha256-ZvDt5bxX6Ga+TQ6kvK5WEn7OQN87KAsMaRrFSdReIm8=", + "lastModified": 1696419054, + "narHash": "sha256-EdR+dIKCfqL3voZUDYwcvgRDOektQB9KbhBVcE0/3Mo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "f4a33546bdb5f81bd6cceb1b3cb19667145fed83", + "rev": "7131f3c223a2d799568e4b278380cd9dac2b8579", "type": "github" }, "original": { From 24c3a2fd0af872ef6bff4d452e40082eebe7fa0f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Oct 2023 14:40:53 +0800 Subject: [PATCH 243/352] shuttler: port to NAC3 --- artiq/coredevice/shuttler.py | 177 ++++++++++-------- .../kasli_shuttler/repository/shuttler.py | 153 ++++++++------- artiq/examples/nac3devices/nac3devices.json | 6 +- artiq/examples/nac3devices/nac3devices.py | 5 + 4 files changed, 191 insertions(+), 150 deletions(-) diff --git a/artiq/coredevice/shuttler.py b/artiq/coredevice/shuttler.py index c6761e0ba..9da784fe7 100644 --- a/artiq/coredevice/shuttler.py +++ b/artiq/coredevice/shuttler.py @@ -1,20 +1,21 @@ -import numpy +from numpy import int32, int64 -from artiq.language.core import * -from artiq.language.types import * +from artiq.language.core import nac3, Kernel, KernelInvariant, kernel, portable, Option, none from artiq.coredevice.rtio import rtio_output, rtio_input_data -from artiq.coredevice import spi2 as spi +from artiq.coredevice.core import Core +from artiq.coredevice.spi2 import * from artiq.language.units import us @portable -def shuttler_volt_to_mu(volt): +def shuttler_volt_to_mu(volt: float) -> int32: """Return the equivalent DAC code. Valid input range is from -10 to 10 - LSB. """ - return round((1 << 16) * (volt / 20.0)) & 0xffff + return round(float(1 << 16) * (volt / 20.0)) & 0xffff +@nac3 class Config: """Shuttler configuration registers interface. @@ -30,10 +31,13 @@ class Config: :param channel: RTIO channel number of this interface. :param core_device: Core device name. """ - kernel_invariants = { - "core", "channel", "target_base", "target_read", - "target_gain", "target_offset", "target_clr" - } + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + target_base: KernelInvariant[int32] + target_read: KernelInvariant[int32] + target_gain: KernelInvariant[int32] + target_offset: KernelInvariant[int32] + target_clr: KernelInvariant[int32] def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) @@ -45,7 +49,7 @@ class Config: self.target_clr = 1 * (1 << 5) @kernel - def set_clr(self, clr): + def set_clr(self, clr: int32): """Set/Unset waveform phase clear bits. Each bit corresponds to a Shuttler waveform generator core. Setting a @@ -59,7 +63,7 @@ class Config: rtio_output(self.target_base | self.target_clr, clr) @kernel - def set_gain(self, channel, gain): + def set_gain(self, channel: int32, gain: int32): """Set the 16-bits pre-DAC gain register of a Shuttler Core channel. The `gain` parameter represents the decimal portion of the gain @@ -72,7 +76,7 @@ class Config: rtio_output(self.target_base | self.target_gain | channel, gain) @kernel - def get_gain(self, channel): + def get_gain(self, channel: int32) -> int32: """Return the pre-DAC gain value of a Shuttler Core channel. :param channel: The Shuttler Core channel. @@ -83,7 +87,7 @@ class Config: return rtio_input_data(self.channel) @kernel - def set_offset(self, channel, offset): + def set_offset(self, channel: int32, offset: int32): """Set the 16-bits pre-DAC offset register of a Shuttler Core channel. .. seealso:: @@ -95,7 +99,7 @@ class Config: rtio_output(self.target_base | self.target_offset | channel, offset) @kernel - def get_offset(self, channel): + def get_offset(self, channel: int32) -> int32: """Return the pre-DAC offset value of a Shuttler Core channel. :param channel: The Shuttler Core channel. @@ -106,6 +110,7 @@ class Config: return rtio_input_data(self.channel) +@nac3 class Volt: """Shuttler Core cubic DC-bias spline. @@ -127,7 +132,9 @@ class Volt: :param channel: RTIO channel number of this DC-bias spline interface. :param core_device: Core device name. """ - kernel_invariants = {"core", "channel", "target_o"} + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + target_o: KernelInvariant[int32] def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) @@ -135,7 +142,7 @@ class Volt: self.target_o = channel << 8 @kernel - def set_waveform(self, a0: TInt32, a1: TInt32, a2: TInt64, a3: TInt64): + def set_waveform(self, a0: int32, a1: int32, a2: int64, a3: int64): """Set the DC-bias spline waveform. Given `a(t)` as defined in :class:`Volt`, the coefficients should be @@ -168,12 +175,12 @@ class Volt: a0, a1, a1 >> 16, - a2 & 0xFFFF, - (a2 >> 16) & 0xFFFF, - (a2 >> 32) & 0xFFFF, - a3 & 0xFFFF, - (a3 >> 16) & 0xFFFF, - (a3 >> 32) & 0xFFFF, + int32(a2 & int64(0xFFFF)), + int32((a2 >> int64(16)) & int64(0xFFFF)), + int32((a2 >> int64(32)) & int64(0xFFFF)), + int32(a3 & int64(0xFFFF)), + int32((a3 >> int64(16)) & int64(0xFFFF)), + int32((a3 >> int64(32)) & int64(0xFFFF)), ] for i in range(len(coef_words)): @@ -181,6 +188,7 @@ class Volt: delay_mu(int64(self.core.ref_multiplier)) +@nac3 class Dds: """Shuttler Core DDS spline. @@ -206,7 +214,9 @@ class Dds: :param channel: RTIO channel number of this DC-bias spline interface. :param core_device: Core device name. """ - kernel_invariants = {"core", "channel", "target_o"} + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + target_o: KernelInvariant[int32] def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) @@ -214,8 +224,8 @@ class Dds: self.target_o = channel << 8 @kernel - def set_waveform(self, b0: TInt32, b1: TInt32, b2: TInt64, b3: TInt64, - c0: TInt32, c1: TInt32, c2: TInt32): + def set_waveform(self, b0: int32, b1: int32, b2: int64, b3: int64, + c0: int32, c1: int32, c2: int32): """Set the DDS spline waveform. Given `b(t)` and `c(t)` as defined in :class:`Dds`, the coefficients @@ -258,12 +268,12 @@ class Dds: b0, b1, b1 >> 16, - b2 & 0xFFFF, - (b2 >> 16) & 0xFFFF, - (b2 >> 32) & 0xFFFF, - b3 & 0xFFFF, - (b3 >> 16) & 0xFFFF, - (b3 >> 32) & 0xFFFF, + int32(b2 & int64(0xFFFF)), + int32((b2 >> int64(16)) & int64(0xFFFF)), + int32((b2 >> int64(32)) & int64(0xFFFF)), + int32(b3 & int64(0xFFFF)), + int32((b3 >> int64(16)) & int64(0xFFFF)), + int32((b3 >> int64(32)) & int64(0xFFFF)), c0, c1, c1 >> 16, @@ -276,13 +286,16 @@ class Dds: delay_mu(int64(self.core.ref_multiplier)) +@nac3 class Trigger: """Shuttler Core spline coefficients update trigger. :param channel: RTIO channel number of the trigger interface. :param core_device: Core device name. """ - kernel_invariants = {"core", "channel", "target_o"} + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + target_o: KernelInvariant[int32] def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) @@ -290,7 +303,7 @@ class Trigger: self.target_o = channel << 8 @kernel - def trigger(self, trig_out): + def trigger(self, trig_out: int32): """Triggers coefficient update of (a) Shuttler Core channel(s). Each bit corresponds to a Shuttler waveform generator core. Setting @@ -304,15 +317,15 @@ class Trigger: rtio_output(self.target_o, trig_out) -RELAY_SPI_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | - 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) +RELAY_SPI_CONFIG = (0*SPI_OFFLINE | 1*SPI_END | + 0*SPI_INPUT | 0*SPI_CS_POLARITY | + 0*SPI_CLK_POLARITY | 0*SPI_CLK_PHASE | + 0*SPI_LSB_FIRST | 0*SPI_HALF_DUPLEX) -ADC_SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | - 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | - 1*spi.SPI_CLK_POLARITY | 1*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) +ADC_SPI_CONFIG = (0*SPI_OFFLINE | 0*SPI_END | + 0*SPI_INPUT | 0*SPI_CS_POLARITY | + 1*SPI_CLK_POLARITY | 1*SPI_CLK_PHASE | + 0*SPI_LSB_FIRST | 0*SPI_HALF_DUPLEX) # SPI clock write and read dividers # CS should assert at least 9.5 ns after clk pulse @@ -335,6 +348,7 @@ _AD4115_REG_CH0 = 0x10 _AD4115_REG_SETUPCON0 = 0x20 +@nac3 class Relay: """Shuttler AFE relay switches. @@ -349,7 +363,8 @@ class Relay: :param spi_device: SPI bus device name. :param core_device: Core device name. """ - kernel_invariant = {"core", "bus"} + core: KernelInvariant[Core] + bus: KernelInvariant[SPIMaster] def __init__(self, dmgr, spi_device, core_device="core"): self.core = dmgr.get(core_device) @@ -366,7 +381,7 @@ class Relay: RELAY_SPI_CONFIG, 16, SPIT_RELAY_WR, CS_RELAY | CS_LED) @kernel - def enable(self, en: TInt32): + def enable(self, en: int32): """Enable/Disable relay switches of corresponding channels. Each bit corresponds to the relay switch of a channel. Asserting a bit @@ -379,20 +394,22 @@ class Relay: self.bus.write(en << 16) +@nac3 class ADC: """Shuttler AFE ADC (AD4115) driver. :param spi_device: SPI bus device name. :param core_device: Core device name. """ - kernel_invariant = {"core", "bus"} + core: KernelInvariant[Core] + bus: KernelInvariant[SPIMaster] def __init__(self, dmgr, spi_device, core_device="core"): self.core = dmgr.get(core_device) self.bus = dmgr.get(spi_device) @kernel - def read_id(self) -> TInt32: + def read_id(self) -> int32: """Read the product ID of the ADC. The expected return value is 0x38DX, the 4 LSbs are don't cares. @@ -414,86 +431,86 @@ class ADC: after the transfer appears to interrupt the start-up sequence. """ self.bus.set_config_mu(ADC_SPI_CONFIG, 32, SPIT_ADC_WR, CS_ADC) - self.bus.write(0xffffffff) - self.bus.write(0xffffffff) + self.bus.write(-1) + self.bus.write(-1) self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END, 32, SPIT_ADC_WR, CS_ADC) - self.bus.write(0xffffffff) + ADC_SPI_CONFIG | SPI_END, 32, SPIT_ADC_WR, CS_ADC) + self.bus.write(-1) @kernel - def read8(self, addr: TInt32) -> TInt32: + def read8(self, addr: int32) -> int32: """Read from 8 bit register. :param addr: Register address. :return: Read-back register content. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, + ADC_SPI_CONFIG | SPI_END | SPI_INPUT, 16, SPIT_ADC_RD, CS_ADC) self.bus.write((addr | 0x40) << 24) return self.bus.read() & 0xff @kernel - def read16(self, addr: TInt32) -> TInt32: + def read16(self, addr: int32) -> int32: """Read from 16 bit register. :param addr: Register address. :return: Read-back register content. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, + ADC_SPI_CONFIG | SPI_END | SPI_INPUT, 24, SPIT_ADC_RD, CS_ADC) self.bus.write((addr | 0x40) << 24) return self.bus.read() & 0xffff @kernel - def read24(self, addr: TInt32) -> TInt32: + def read24(self, addr: int32) -> int32: """Read from 24 bit register. :param addr: Register address. :return: Read-back register content. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, + ADC_SPI_CONFIG | SPI_END | SPI_INPUT, 32, SPIT_ADC_RD, CS_ADC) self.bus.write((addr | 0x40) << 24) return self.bus.read() & 0xffffff @kernel - def write8(self, addr: TInt32, data: TInt32): + def write8(self, addr: int32, data: int32): """Write to 8 bit register. :param addr: Register address. :param data: Data to be written. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END, 16, SPIT_ADC_WR, CS_ADC) + ADC_SPI_CONFIG | SPI_END, 16, SPIT_ADC_WR, CS_ADC) self.bus.write(addr << 24 | (data & 0xff) << 16) @kernel - def write16(self, addr: TInt32, data: TInt32): + def write16(self, addr: int32, data: int32): """Write to 16 bit register. :param addr: Register address. :param data: Data to be written. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END, 24, SPIT_ADC_WR, CS_ADC) + ADC_SPI_CONFIG | SPI_END, 24, SPIT_ADC_WR, CS_ADC) self.bus.write(addr << 24 | (data & 0xffff) << 8) @kernel - def write24(self, addr: TInt32, data: TInt32): + def write24(self, addr: int32, data: int32): """Write to 24 bit register. :param addr: Register address. :param data: Data to be written. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END, 32, SPIT_ADC_WR, CS_ADC) + ADC_SPI_CONFIG | SPI_END, 32, SPIT_ADC_WR, CS_ADC) self.bus.write(addr << 24 | (data & 0xffffff)) @kernel - def read_ch(self, channel: TInt32) -> TFloat: + def read_ch(self, channel: int32) -> float: """Sample a Shuttler channel on the AFE. It performs a single conversion using profile 0 and setup 0, on the @@ -507,9 +524,9 @@ class ADC: self.write16(_AD4115_REG_SETUPCON0, 0x1300) self.single_conversion() - delay(100*us) + self.core.delay(100.*us) adc_code = self.read24(_AD4115_REG_DATA) - return ((adc_code / (1 << 23)) - 1) * 2.5 / 0.1 + return ((float(adc_code) / float(1 << 23)) - 1.) * 2.5 / 0.1 @kernel def single_conversion(self): @@ -560,10 +577,10 @@ class ADC: self.reset() # Although the datasheet claims 500 us reset wait time, only waiting # for ~500 us can result in DOUT pin stuck in high - delay(2500*us) + self.core.delay(2500.*us) @kernel - def calibrate(self, volts, trigger, config, samples=[-5.0, 0.0, 5.0]): + def calibrate(self, volts: list[Volt], trigger: Trigger, config: Config, samples: Option[list[float]] = none): """Calibrate the Shuttler waveform generator using the ADC on the AFE. It finds the average slope rate and average offset by samples, and @@ -588,33 +605,35 @@ class ADC: :param samples: A list of sample voltages for calibration. There must be at least 2 samples to perform slope rate calculation. """ - assert len(volts) == 16 - assert len(samples) > 1 + samples_l = samples.unwrap() if samples.is_some() else [-5.0, 0.0, 5.0] - measurements = [0.0] * len(samples) + assert len(volts) == 16 + assert len(samples_l) > 1 + + measurements = [0.0 for _ in range(len(samples_l))] for ch in range(16): # Find the average slope rate and offset - for i in range(len(samples)): + for i in range(len(samples_l)): self.core.break_realtime() volts[ch].set_waveform( - shuttler_volt_to_mu(samples[i]), 0, 0, 0) + shuttler_volt_to_mu(samples_l[i]), 0, int64(0), int64(0)) trigger.trigger(1 << ch) measurements[i] = self.read_ch(ch) # Find the average output slope slope_sum = 0.0 - for i in range(len(samples) - 1): - slope_sum += (measurements[i+1] - measurements[i])/(samples[i+1] - samples[i]) - slope_avg = slope_sum / (len(samples) - 1) + for i in range(len(samples_l) - 1): + slope_sum += (measurements[i+1] - measurements[i])/(samples_l[i+1] - samples_l[i]) + slope_avg = slope_sum / float(len(samples_l) - 1) - gain_code = int32(1 / slope_avg * (2 ** 16)) & 0xffff + gain_code = int32(1. / slope_avg * float(2 ** 16)) & 0xffff # Scale the measurements by 1/slope, find average offset offset_sum = 0.0 - for i in range(len(samples)): - offset_sum += (measurements[i] / slope_avg) - samples[i] - offset_avg = offset_sum / len(samples) + for i in range(len(samples_l)): + offset_sum += (measurements[i] / slope_avg) - samples_l[i] + offset_avg = offset_sum / float(len(samples_l)) offset_code = shuttler_volt_to_mu(-offset_avg) diff --git a/artiq/examples/kasli_shuttler/repository/shuttler.py b/artiq/examples/kasli_shuttler/repository/shuttler.py index 22a3a776e..9a0b4e517 100644 --- a/artiq/examples/kasli_shuttler/repository/shuttler.py +++ b/artiq/examples/kasli_shuttler/repository/shuttler.py @@ -1,61 +1,82 @@ -from artiq.experiment import * -from artiq.coredevice.shuttler import shuttler_volt_to_mu +from numpy import int32, int64 -DAC_Fs_MHZ = 125 +from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut +from artiq.coredevice.shuttler import ( + shuttler_volt_to_mu, + Config as ShuttlerConfig, + Trigger as ShuttlerTrigger, + Volt as ShuttlerDCBias, + Dds as ShuttlerDDS, + Relay as ShuttlerRelay, + ADC as ShuttlerADC) + + +DAC_Fs_MHZ = 125. CORDIC_GAIN = 1.64676 @portable -def shuttler_phase_offset(offset_degree): - return round(offset_degree / 360 * (2 ** 16)) +def shuttler_phase_offset(offset_degree: float) -> int32: + return round(offset_degree / 360. * float(2 ** 16)) @portable -def shuttler_freq_mu(freq_mhz): +def shuttler_freq_mu(freq_mhz: float) -> int32: return round(float(2) ** 32 / DAC_Fs_MHZ * freq_mhz) @portable -def shuttler_chirp_rate_mu(freq_mhz_per_us): +def shuttler_chirp_rate_mu(freq_mhz_per_us: float) -> int32: return round(float(2) ** 32 * freq_mhz_per_us / (DAC_Fs_MHZ ** 2)) @portable -def shuttler_freq_sweep(start_f_MHz, end_f_MHz, time_us): - return shuttler_chirp_rate_mu((end_f_MHz - start_f_MHz)/(time_us)) +def shuttler_freq_sweep(start_f_MHz: float, end_f_MHz: float, time_us: float) -> int32: + return shuttler_chirp_rate_mu((end_f_MHz - start_f_MHz)/time_us) @portable -def shuttler_volt_amp_mu(volt): +def shuttler_volt_amp_mu(volt: float) -> int32: return shuttler_volt_to_mu(volt) @portable -def shuttler_volt_damp_mu(volt_per_us): - return round(float(2) ** 32 * (volt_per_us / 20) / DAC_Fs_MHZ) +def shuttler_volt_damp_mu(volt_per_us: float) -> int32: + return round(float(2) ** 32 * (volt_per_us / 20.) / DAC_Fs_MHZ) @portable -def shuttler_volt_ddamp_mu(volt_per_us_square): - return round(float(2) ** 48 * (volt_per_us_square / 20) * 2 / (DAC_Fs_MHZ ** 2)) +def shuttler_volt_ddamp_mu(volt_per_us_square: float) -> int64: + return round64(float(2) ** 48 * (volt_per_us_square / 20.) * 2. / (DAC_Fs_MHZ ** 2)) @portable -def shuttler_volt_dddamp_mu(volt_per_us_cube): - return round(float(2) ** 48 * (volt_per_us_cube / 20) * 6 / (DAC_Fs_MHZ ** 3)) +def shuttler_volt_dddamp_mu(volt_per_us_cube: float) -> int64: + return round64(float(2) ** 48 * (volt_per_us_cube / 20.) * 6. / (DAC_Fs_MHZ ** 3)) @portable -def shuttler_dds_amp_mu(volt): +def shuttler_dds_amp_mu(volt: float) -> int32: return shuttler_volt_amp_mu(volt / CORDIC_GAIN) @portable -def shuttler_dds_damp_mu(volt_per_us): +def shuttler_dds_damp_mu(volt_per_us: float) -> int32: return shuttler_volt_damp_mu(volt_per_us / CORDIC_GAIN) @portable -def shuttler_dds_ddamp_mu(volt_per_us_square): +def shuttler_dds_ddamp_mu(volt_per_us_square: float) -> int64: return shuttler_volt_ddamp_mu(volt_per_us_square / CORDIC_GAIN) @portable -def shuttler_dds_dddamp_mu(volt_per_us_cube): +def shuttler_dds_dddamp_mu(volt_per_us_cube: float) -> int64: return shuttler_volt_dddamp_mu(volt_per_us_cube / CORDIC_GAIN) +@nac3 class Shuttler(EnvExperiment): + core: KernelInvariant[Core] + shuttler0_leds: KernelInvariant[list[TTLOut]] + shuttler0_config: KernelInvariant[ShuttlerConfig] + shuttler0_trigger: KernelInvariant[ShuttlerTrigger] + shuttler0_volt: KernelInvariant[list[ShuttlerDCBias]] + shuttler0_dds: KernelInvariant[list[ShuttlerDDS]] + shuttler0_relay: KernelInvariant[ShuttlerRelay] + shuttler0_adc: KernelInvariant[ShuttlerADC] + def build(self): self.setattr_device("core") - self.setattr_device("core_dma") self.setattr_device("scheduler") self.shuttler0_leds = [ self.get_device("shuttler0_led{}".format(i)) for i in range(2) ] self.setattr_device("shuttler0_config") @@ -64,12 +85,6 @@ class Shuttler(EnvExperiment): self.shuttler0_dds = [ self.get_device("shuttler0_dds{}".format(i)) for i in range(16) ] self.setattr_device("shuttler0_relay") self.setattr_device("shuttler0_adc") - - - @kernel - def record(self): - with self.core_dma.record("example_waveform"): - self.example_waveform() @kernel def init(self): @@ -84,35 +99,33 @@ class Shuttler(EnvExperiment): self.core.break_realtime() self.init() - self.record() - example_waveform_handle = self.core_dma.get_handle("example_waveform") - - print("Example Waveforms are on OUT0 and OUT1") + print_rpc("Example Waveforms are on OUT0 and OUT1") self.core.break_realtime() - while not(self.scheduler.check_termination()): - delay(1*s) - self.core_dma.playback_handle(example_waveform_handle) + #while not(self.scheduler.check_termination()): + while True: + self.core.delay(1.*s) + self.example_waveform() @kernel def shuttler_reset(self): for i in range(16): self.shuttler_channel_reset(i) # To avoid RTIO Underflow - delay(50*us) + self.core.delay(50.*us) @kernel - def shuttler_channel_reset(self, ch): + def shuttler_channel_reset(self, ch: int32): self.shuttler0_volt[ch].set_waveform( a0=0, a1=0, - a2=0, - a3=0, + a2=int64(0), + a3=int64(0), ) self.shuttler0_dds[ch].set_waveform( b0=0, b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=0, c1=0, c2=0, @@ -163,13 +176,13 @@ class Shuttler(EnvExperiment): ## Step 2 ## start_f_MHz = 0.01 end_f_MHz = 0.05 - duration_us = 500 + duration_us = 500. # OUT0 and OUT1 have their frequency and phase aligned at 500us self.shuttler0_dds[0].set_waveform( b0=shuttler_dds_amp_mu(1.0), b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=0, c1=shuttler_freq_mu(start_f_MHz), c2=shuttler_freq_sweep(start_f_MHz, end_f_MHz, duration_us), @@ -177,22 +190,22 @@ class Shuttler(EnvExperiment): self.shuttler0_dds[1].set_waveform( b0=shuttler_dds_amp_mu(1.0), b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=0, c1=shuttler_freq_mu(end_f_MHz), c2=0, ) self.shuttler0_trigger.trigger(0b11) - delay(500*us) + self.core.delay(500.*us) ## Step 3 ## # OUT0 and OUT1 has 180 degree phase difference self.shuttler0_dds[0].set_waveform( b0=shuttler_dds_amp_mu(1.0), b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=shuttler_phase_offset(180.0), c1=shuttler_freq_mu(end_f_MHz), c2=0, @@ -200,7 +213,7 @@ class Shuttler(EnvExperiment): # Phase and Output Setting of OUT1 is retained # if the channel is not triggered or config is not cleared self.shuttler0_trigger.trigger(0b1) - delay(500*us) + self.core.delay(500.*us) ## Step 4 ## # b(0) = 0, b(250) = 8.545, b(500) = 0 @@ -208,7 +221,7 @@ class Shuttler(EnvExperiment): b0=0, b1=shuttler_dds_damp_mu(0.06835937), b2=shuttler_dds_ddamp_mu(-0.0001367187), - b3=0, + b3=int64(0), c0=0, c1=shuttler_freq_mu(end_f_MHz), c2=0, @@ -217,26 +230,26 @@ class Shuttler(EnvExperiment): b0=0, b1=shuttler_dds_damp_mu(0.06835937), b2=shuttler_dds_ddamp_mu(-0.0001367187), - b3=0, + b3=int64(0), c0=0, c1=0, c2=0, ) self.shuttler0_trigger.trigger(0b11) - delay(500*us) + self.core.delay(500.*us) ## Step 5 ## self.shuttler0_volt[0].set_waveform( a0=shuttler_volt_amp_mu(-5.0), a1=int32(shuttler_volt_damp_mu(0.01)), - a2=0, - a3=0, + a2=int64(0), + a3=int64(0), ) self.shuttler0_dds[0].set_waveform( b0=shuttler_dds_amp_mu(1.0), b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=0, c1=shuttler_freq_mu(end_f_MHz), c2=0, @@ -244,59 +257,59 @@ class Shuttler(EnvExperiment): self.shuttler0_volt[1].set_waveform( a0=shuttler_volt_amp_mu(-5.0), a1=int32(shuttler_volt_damp_mu(0.01)), - a2=0, - a3=0, + a2=int64(0), + a3=int64(0), ) self.shuttler0_dds[1].set_waveform( b0=0, b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=0, c1=0, c2=0, ) self.shuttler0_trigger.trigger(0b11) - delay(1000*us) + self.core.delay(1000.*us) ## Step 6 ## self.shuttler0_volt[0].set_waveform( a0=shuttler_volt_amp_mu(-2.5), a1=int32(shuttler_volt_damp_mu(0.01)), - a2=0, - a3=0, + a2=int64(0), + a3=int64(0), ) self.shuttler0_dds[0].set_waveform( b0=0, b1=shuttler_dds_damp_mu(0.06835937), b2=shuttler_dds_ddamp_mu(-0.0001367187), - b3=0, + b3=int64(0), c0=0, c1=shuttler_freq_mu(start_f_MHz), c2=shuttler_freq_sweep(start_f_MHz, end_f_MHz, duration_us), ) self.shuttler0_trigger.trigger(0b1) self.shuttler_channel_reset(1) - delay(500*us) + self.core.delay(500.*us) ## Step 7 ## self.shuttler0_volt[0].set_waveform( a0=shuttler_volt_amp_mu(2.5), a1=int32(shuttler_volt_damp_mu(-0.01)), - a2=0, - a3=0, + a2=int64(0), + a3=int64(0), ) self.shuttler0_dds[0].set_waveform( b0=0, b1=shuttler_dds_damp_mu(-0.06835937), b2=shuttler_dds_ddamp_mu(0.0001367187), - b3=0, + b3=int64(0), c0=shuttler_phase_offset(180.0), c1=shuttler_freq_mu(end_f_MHz), c2=shuttler_freq_sweep(end_f_MHz, start_f_MHz, duration_us), ) self.shuttler0_trigger.trigger(0b1) - delay(500*us) + self.core.delay(500.*us) ## Step 8 ## self.shuttler0_relay.enable(0) @@ -308,7 +321,7 @@ class Shuttler(EnvExperiment): for i in range(2): for j in range(3): self.shuttler0_leds[i].pulse(.1*s) - delay(.1*s) + self.core.delay(.1*s) @kernel def relay_init(self): diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json index 7fda9ca78..d9b148ddb 100644 --- a/artiq/examples/nac3devices/nac3devices.json +++ b/artiq/examples/nac3devices/nac3devices.json @@ -3,7 +3,7 @@ "min_artiq_version": "9.0", "variant": "nac3devices", "hw_rev": "v2.0", - "base": "standalone", + "drtio_role": "master", "core_addr": "192.168.1.70", "peripherals": [ { @@ -51,6 +51,10 @@ { "type": "phaser", "ports": [10] + }, + { + "type": "shuttler", + "ports": [11] } ] } diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index 1f2d54cc7..76d3969cf 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -14,6 +14,7 @@ from artiq.coredevice.edge_counter import EdgeCounter from artiq.coredevice.grabber import Grabber from artiq.coredevice.fastino import Fastino from artiq.coredevice.phaser import Phaser +from artiq.coredevice.shuttler import Volt as ShuttlerDCBias, Dds as ShuttlerDDS @nac3 @@ -34,6 +35,8 @@ class NAC3Devices(EnvExperiment): grabber0: KernelInvariant[Grabber] fastino0: KernelInvariant[Fastino] phaser0: KernelInvariant[Phaser] + shuttler0_volt0: KernelInvariant[ShuttlerDCBias] + shuttler0_dds0: KernelInvariant[ShuttlerDDS] def build(self): self.setattr_device("core") @@ -52,6 +55,8 @@ class NAC3Devices(EnvExperiment): self.setattr_device("grabber0") self.setattr_device("fastino0") self.setattr_device("phaser0") + self.setattr_device("shuttler0_volt0") + self.setattr_device("shuttler0_dds0") @kernel def run(self): From d96dc11b25d913ba5d30eb9d46462c73302aa60e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Oct 2023 14:41:26 +0800 Subject: [PATCH 244/352] shuttler: use scheduler --- artiq/examples/kasli_shuttler/repository/shuttler.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/examples/kasli_shuttler/repository/shuttler.py b/artiq/examples/kasli_shuttler/repository/shuttler.py index 9a0b4e517..730573d95 100644 --- a/artiq/examples/kasli_shuttler/repository/shuttler.py +++ b/artiq/examples/kasli_shuttler/repository/shuttler.py @@ -101,8 +101,7 @@ class Shuttler(EnvExperiment): print_rpc("Example Waveforms are on OUT0 and OUT1") self.core.break_realtime() - #while not(self.scheduler.check_termination()): - while True: + while not(self.scheduler.check_termination()): self.core.delay(1.*s) self.example_waveform() From 1fb5ecf7edf360211f7475d4b4dc15ca16fb30c1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Oct 2023 14:56:57 +0800 Subject: [PATCH 245/352] flake: update dependencies --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 22377d044..33156d726 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1696500173, - "narHash": "sha256-hOPpKVWSEIAhjnb7WQsnklIsj3PuVN2d1G0KfXdhxBw=", + "lastModified": 1696566243, + "narHash": "sha256-KsnvxNHGa67FOEn+2OkjHlnGtPtD0bVlBcYv9zPZZEc=", "ref": "refs/heads/master", - "rev": "901e921e00eb00c067a453b277329b36b7041891", - "revCount": 873, + "rev": "50230e61f3829881581b6ff554663b543eb82ad7", + "revCount": 882, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From fa5666fb0d76f551ccf88a8bf3dd7d80be97ff6e Mon Sep 17 00:00:00 2001 From: David Mak Date: Mon, 16 Oct 2023 14:01:00 +0800 Subject: [PATCH 246/352] docs: Add instructions to run with custom NAC3 Signed-off-by: David Mak --- doc/manual/developing.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index cea0c3e9b..9079f1adf 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -20,3 +20,27 @@ ARTIQ itself does not depend on Nix, and it is also possible to compile everythi * 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). + +Testing Custom NAC3 Builds +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To test a version of NAC3 from source using ARTIQ kernels or test cases on real hardware, follow these instructions: + +1. Clone or download the source code of NAC3. This path will be referred to as ````. +2. Build NAC3 from source, e.g.: + +.. code-block:: + + $ cd + $ nix develop + [nix-shell] $ cargo clean && cargo build --release + +3. Symlink ``nac3artiq.so`` to ``libnac3artiq.so``, i.e. ``ln -s target/release/libnac3artiq.so target/release/nac3artiq.so`` +4. Enter the development environment for ARTIQ, e.g. ``cd && nix develop`` +5. Run the Python command, overriding ``PYTHONPATH`` with the directory containing ``nac3artiq.so``, e.g.: + +.. code-block:: + + [nix-shell] $ PYTHONPATH="/target/release:$PYTHONPATH" python ... + +This will run the ARTIQ command using the custom build of NAC3. From 700a20ad0831b43b4ae6022b81836317bd61351a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 28 Oct 2023 03:50:03 +0800 Subject: [PATCH 247/352] flake: update dependencies --- flake.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/flake.lock b/flake.lock index 33156d726..6dbff1770 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1696566243, - "narHash": "sha256-KsnvxNHGa67FOEn+2OkjHlnGtPtD0bVlBcYv9zPZZEc=", + "lastModified": 1698239362, + "narHash": "sha256-RzvXRJvGJnzYO7N/q5nihJtX8nozarvcsWAV1bfTVNw=", "ref": "refs/heads/master", - "rev": "50230e61f3829881581b6ff554663b543eb82ad7", - "revCount": 882, + "rev": "ea2ab0ef7c9fbaf7d57b5f7f2986f474b20c98e3", + "revCount": 893, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,16 +79,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1696419054, - "narHash": "sha256-EdR+dIKCfqL3voZUDYwcvgRDOektQB9KbhBVcE0/3Mo=", + "lastModified": 1698233941, + "narHash": "sha256-n66he1jg9pt/zkVACpWwVMYTIkGmF4jOM764mMj0ffw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7131f3c223a2d799568e4b278380cd9dac2b8579", + "rev": "545857e74921a41af587931bd80dfed5541c3cbf", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-unstable", + "ref": "master", "repo": "nixpkgs", "type": "github" } @@ -111,11 +111,11 @@ ] }, "locked": { - "lastModified": 1693473454, - "narHash": "sha256-kr8Ur6JNW/xVRHdPn3ou980IAxg/n+f3ZQBHuJ1uaC4=", + "lastModified": 1697528004, + "narHash": "sha256-FFa2MbhAJEjwY58uOs0swvgymfjubHyWba6Q0X6CbB0=", "owner": "m-labs", "repo": "sipyco", - "rev": "5467dcf9738673ab9a49e6f2377bda7c551b5f90", + "rev": "c0a7ed350ccfb85474217057fc47b3f258ca8d99", "type": "github" }, "original": { @@ -127,11 +127,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1693990700, - "narHash": "sha256-qJLA03QcZ5S9DrqrseuzIQBTWS7rjAbYJxLYZEQ8rxA=", + "lastModified": 1697013661, + "narHash": "sha256-qNCqgWyE4vTDmyjE2XMJqW1djuBxT25A36AzQfZqluU=", "owner": "m-labs", "repo": "migen", - "rev": "2cfee3e0db6fdca9b5918686ea77c93252e7cebd", + "rev": "aadc19df93b7aa9ca761aaebbb98a11e0cf2d7c7", "type": "github" }, "original": { From 92391c476382516c009b1e3b1b14ebe7aca54af5 Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Mon, 30 Oct 2023 14:09:31 +0800 Subject: [PATCH 248/352] flake: fix and upgrade wavedrom (closes #2266) Signed-off-by: Florian Agbuya --- flake.nix | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 8f5a21e3f..509ad62bd 100644 --- a/flake.nix +++ b/flake.nix @@ -277,12 +277,13 @@ sphinxcontrib-wavedrom = pkgs.python3Packages.buildPythonPackage rec { pname = "sphinxcontrib-wavedrom"; - version = "3.0.2"; + version = "3.0.4"; + format = "pyproject"; src = pkgs.python3Packages.fetchPypi { inherit pname version; - sha256 = "sha256-ukZd3ajt0Sx3LByof4R80S31F5t1yo+L8QUADrMMm2A="; + sha256 = "sha256-0zTHVBr9kXwMEo4VRTFsxdX2HI31DxdHfLUHCQmw1Ko="; }; - buildInputs = [ pkgs.python3Packages.setuptools_scm ]; + nativeBuildInputs = [ pkgs.python3Packages.setuptools-scm ]; propagatedBuildInputs = (with pkgs.python3Packages; [ wavedrom sphinx xcffib cairosvg ]); }; latex-artiq-manual = pkgs.texlive.combine { From d0a3ba2bc00f04f68cb719a72a193365f17aef37 Mon Sep 17 00:00:00 2001 From: David Mak Date: Mon, 30 Oct 2023 15:08:29 +0800 Subject: [PATCH 249/352] artiq_sinara_tester: Refactor Almazny to AlmaznyLegacy The class was renamed in 45cd438fb875a337f6ac7f06a2b0e5e1a7f1706e. Signed-off-by: David Mak --- artiq/frontend/artiq_sinara_tester.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) mode change 100755 => 100644 artiq/frontend/artiq_sinara_tester.py diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py old mode 100755 new mode 100644 index 2a2d91cc4..ed6aed946 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -13,7 +13,8 @@ from artiq.coredevice.core import Core from artiq.coredevice.ttl import TTLOut, TTLInOut from artiq.coredevice.urukul import CPLD as UrukulCPLD from artiq.coredevice.ad9910 import AD9910, SyncDataEeprom -from artiq.coredevice.mirny import Mirny, Almazny +from artiq.coredevice.mirny import Mirny +from artiq.coredevice.almazny import AlmaznyLegacy from artiq.coredevice.adf5356 import ADF5356 from artiq.coredevice.sampler import Sampler from artiq.coredevice.zotino import Zotino @@ -376,23 +377,23 @@ class SinaraTester(EnvExperiment): channel.pulse(100.*ms) self.core.delay(100.*ms) @kernel - def init_almazny(self, almazny: Almazny): + def init_almazny(self, almazny: AlmaznyLegacy): self.core.break_realtime() almazny.init() almazny.output_toggle(True) @kernel - def almazny_set_attenuators_mu(self, almazny: Almazny, ch: int32, atts: int32): + def almazny_set_attenuators_mu(self, almazny: AlmaznyLegacy, ch: int32, atts: int32): self.core.break_realtime() almazny.set_att_mu(ch, atts) @kernel - def almazny_set_attenuators(self, almazny: Almazny, ch: int32, atts: float): + def almazny_set_attenuators(self, almazny: AlmaznyLegacy, ch: int32, atts: float): self.core.break_realtime() almazny.set_att(ch, atts) @kernel - def almazny_toggle_output(self, almazny: Almazny, rf_on: bool): + def almazny_toggle_output(self, almazny: AlmaznyLegacy, rf_on: bool): self.core.break_realtime() almazny.output_toggle(rf_on) From e60d5cab057cf3788d8a3551d12f731cf3c23f12 Mon Sep 17 00:00:00 2001 From: David Mak Date: Mon, 30 Oct 2023 15:10:09 +0800 Subject: [PATCH 250/352] artiq_sinara_tester: Fix NAC3 compilation failures - Fix incorrect types for bin-op/function call - Explicitly invoke exception constructor for raise statement Signed-off-by: David Mak --- artiq/frontend/artiq_sinara_tester.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) mode change 100644 => 100755 artiq/frontend/artiq_sinara_tester.py diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py old mode 100644 new mode 100755 index ed6aed946..d8f445885 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -595,10 +595,10 @@ class SinaraTester(EnvExperiment): if phaser.gw_rev == PHASER_GW_BASE: phaser.channel[0].set_duc_frequency(duc) phaser.channel[0].set_duc_cfg() - phaser.channel[0].set_att(6*dB) + phaser.channel[0].set_att(6.*dB) phaser.channel[1].set_duc_frequency(-duc) phaser.channel[1].set_duc_cfg() - phaser.channel[1].set_att(6*dB) + phaser.channel[1].set_att(6.*dB) phaser.duc_stb() self.core.delay(1.*ms) for i in range(len(osc)): @@ -609,20 +609,20 @@ class SinaraTester(EnvExperiment): self.core.delay(1.*ms) elif phaser.gw_rev == PHASER_GW_MIQRO: for ch in range(2): - phaser.channel[ch].set_att(6*dB) + phaser.channel[ch].set_att(6.*dB) phaser.channel[ch].set_duc_cfg() - sign = 1. - 2.*ch + sign = 1. - 2.*float(ch) for i in range(len(osc)): phaser.channel[ch].miqro.set_profile(i, profile=1, - frequency=sign*(duc + osc[i]), amplitude=1./len(osc)) + frequency=sign*(duc + osc[i]), amplitude=1./float(len(osc))) self.core.delay(100.*us) phaser.channel[ch].miqro.set_window( - start=0x000, iq=[[1., 0.]], order=0, tail=0) + start=0x000, iq=[(1., 0.)], order=0, tail=False) phaser.channel[ch].miqro.pulse( window=0x000, profiles=[1 for _ in range(len(osc))]) self.core.delay(1.*ms) else: - raise ValueError + raise ValueError() @kernel def phaser_led_wave(self, phasers: list[Phaser]): From c0d79a0ce2fea4028cdc17e24b1f067b5556920d Mon Sep 17 00:00:00 2001 From: David Mak Date: Mon, 30 Oct 2023 14:20:29 +0800 Subject: [PATCH 251/352] embedding_map: Update exception list to match NAC3 Signed-off-by: David Mak --- artiq/language/embedding_map.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/artiq/language/embedding_map.py b/artiq/language/embedding_map.py index 050925db9..14833b730 100644 --- a/artiq/language/embedding_map.py +++ b/artiq/language/embedding_map.py @@ -11,16 +11,23 @@ class EmbeddingMap: # must be kept in sync with EXCEPTION_ID_LOOKUP in artiq/firmware/ksupport/eh_artiq.rs, # and src/runtime/src/eh_artiq.rs (Zynq) self.preallocate_runtime_exception_names(["RuntimeError", - "RTIOUnderflow", - "RTIOOverflow", - "RTIODestinationUnreachable", - "DMAError", - "I2CError", - "CacheError", - "SPIError", - "0:ZeroDivisionError", - "0:IndexError", - "0:UnwrapNoneError"]) + "RTIOUnderflow", + "RTIOOverflow", + "RTIODestinationUnreachable", + "DMAError", + "I2CError", + "CacheError", + "SPIError", + "0:ZeroDivisionError", + "0:IndexError", + "0:ValueError", + "0:RuntimeError", + "0:AssertionError", + "0:KeyError", + "0:NotImplementedError", + "0:OverflowError", + "0:IOError", + "0:UnwrapNoneError"]) def preallocate_runtime_exception_names(self, names): for i, name in enumerate(names): From 4784a42030a594d37754c3d002e83f8a64cb2cba Mon Sep 17 00:00:00 2001 From: David Mak Date: Wed, 1 Nov 2023 15:37:54 +0800 Subject: [PATCH 252/352] test_analyzer: Enable test_ttl_pulse test case Now that the issue is fixed. Signed-off-by: David Mak --- artiq/test/coredevice/test_analyzer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/test/coredevice/test_analyzer.py b/artiq/test/coredevice/test_analyzer.py index 67f5a8bc8..776ee3eef 100644 --- a/artiq/test/coredevice/test_analyzer.py +++ b/artiq/test/coredevice/test_analyzer.py @@ -54,7 +54,6 @@ class WriteLog(EnvExperiment): class AnalyzerTest(ExperimentCase): - @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/298") def test_ttl_pulse(self): core_host = self.device_mgr.get_desc("core")["arguments"]["host"] From c1574ef7fee501e6cfb879d9d4b94b51fd4fc40c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 1 Nov 2023 17:43:16 +0800 Subject: [PATCH 253/352] flake: update nixpkgs --- flake.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/flake.lock b/flake.lock index 6dbff1770..d575dcbe9 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1698239362, - "narHash": "sha256-RzvXRJvGJnzYO7N/q5nihJtX8nozarvcsWAV1bfTVNw=", + "lastModified": 1698825227, + "narHash": "sha256-oAx9tPCRq5pClSZqItW0qFmfmvRXbVid+FhPBelJUAw=", "ref": "refs/heads/master", - "rev": "ea2ab0ef7c9fbaf7d57b5f7f2986f474b20c98e3", - "revCount": 893, + "rev": "e546535df04ba1737dbefdc2ef82c268519ffc75", + "revCount": 903, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,16 +79,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1698233941, - "narHash": "sha256-n66he1jg9pt/zkVACpWwVMYTIkGmF4jOM764mMj0ffw=", + "lastModified": 1698553279, + "narHash": "sha256-T/9P8yBSLcqo/v+FTOBK+0rjzjPMctVymZydbvR/Fak=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "545857e74921a41af587931bd80dfed5541c3cbf", + "rev": "90e85bc7c1a6fc0760a94ace129d3a1c61c3d035", "type": "github" }, "original": { "owner": "NixOS", - "ref": "master", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } From f3655aa0847f1933a8efa88c8d9e715dd530070d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 4 Nov 2023 13:44:23 +0800 Subject: [PATCH 254/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index d575dcbe9..c0be6ea00 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1698825227, - "narHash": "sha256-oAx9tPCRq5pClSZqItW0qFmfmvRXbVid+FhPBelJUAw=", + "lastModified": 1699076564, + "narHash": "sha256-IE/+l0+pDbohP8DEr05lieF2beUFKO3kgdecNtGnBIw=", "ref": "refs/heads/master", - "rev": "e546535df04ba1737dbefdc2ef82c268519ffc75", - "revCount": 903, + "rev": "c2ab6b58ffdcb899d7656f52bcbb379c9c4804ed", + "revCount": 924, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 4fa0419c8262099ef297bf8b417f51f4095b2df5 Mon Sep 17 00:00:00 2001 From: David Mak Date: Tue, 31 Oct 2023 11:44:31 +0800 Subject: [PATCH 255/352] core: Add legacy_parallel Signed-off-by: David Mak --- artiq/language/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/language/core.py b/artiq/language/core.py index 379f57aaa..bcf4a7f8b 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -18,7 +18,7 @@ __all__ = [ "print_rpc", "Option", "Some", "none", "UnwrapNoneError", "set_time_manager", - "parallel", "sequential", + "parallel", "legacy_parallel", "sequential", "delay_mu", "now_mu", "at_mu", "set_watchdog_factory", "watchdog", "TerminationRequested", ] @@ -211,6 +211,7 @@ class _SequentialContextManager: _time_manager.exit() parallel = _ParallelContextManager() +legacy_parallel = _ParallelContextManager() sequential = _SequentialContextManager() From 42a9cc725b054f85d91e64219dcd85e6ed673d96 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 8 Nov 2023 17:30:55 +0800 Subject: [PATCH 256/352] flake: update dependencies --- flake.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/flake.lock b/flake.lock index c0be6ea00..a1b80bb7c 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1699076564, - "narHash": "sha256-IE/+l0+pDbohP8DEr05lieF2beUFKO3kgdecNtGnBIw=", + "lastModified": 1699435769, + "narHash": "sha256-zrtjjYibnO9ukgEEBXAT/3o8vWsFN+IY5zad9sBaLAg=", "ref": "refs/heads/master", - "rev": "c2ab6b58ffdcb899d7656f52bcbb379c9c4804ed", - "revCount": 924, + "rev": "1ca4de99b951a50d129b8d07a3d9d896596f1c3c", + "revCount": 927, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,11 +79,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1698553279, - "narHash": "sha256-T/9P8yBSLcqo/v+FTOBK+0rjzjPMctVymZydbvR/Fak=", + "lastModified": 1699343069, + "narHash": "sha256-s7BBhyLA6MI6FuJgs4F/SgpntHBzz40/qV0xLPW6A1Q=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "90e85bc7c1a6fc0760a94ace129d3a1c61c3d035", + "rev": "ec750fd01963ab6b20ee1f0cb488754e8036d89d", "type": "github" }, "original": { @@ -127,11 +127,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1697013661, - "narHash": "sha256-qNCqgWyE4vTDmyjE2XMJqW1djuBxT25A36AzQfZqluU=", + "lastModified": 1699335478, + "narHash": "sha256-BsubN4Mfdj02QPK6ZCrl+YOaSg7DaLQdSCVP49ztWik=", "owner": "m-labs", "repo": "migen", - "rev": "aadc19df93b7aa9ca761aaebbb98a11e0cf2d7c7", + "rev": "fd0bf5855a1367eab14b0d6f7f8266178e25d78e", "type": "github" }, "original": { @@ -143,11 +143,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1693709836, - "narHash": "sha256-YiCk05RYLzZu1CYkQ2r7XtjwVEqkUGTQn388uOls9tI=", + "lastModified": 1699352904, + "narHash": "sha256-SglyTmXOPv8jJOjwAjJrj/WhAkItQfUbvKfUqrynwRg=", "ref": "refs/heads/master", - "rev": "58dc4ee60d165ce9145cf3d904241fc154b6407f", - "revCount": 2448, + "rev": "a53859f2167c31ab5225b6c09f30cf05527b94f4", + "revCount": 2452, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From 5bbac04bef170cddb608b5dc8d9e6778cc7b31e8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 11 Nov 2023 11:08:52 +0800 Subject: [PATCH 257/352] coredevice: use new nac3 binary shift typing rules --- artiq/coredevice/ad9910.py | 6 +++--- artiq/coredevice/ad9912.py | 6 +++--- artiq/coredevice/adf5356.py | 8 ++++---- artiq/coredevice/shuttler.py | 16 ++++++++-------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index e2600d6ac..39d2adfa6 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -332,7 +332,7 @@ class AD9910: self.bus.write(0) hi = self.bus.read() lo = self.bus.read() - return (int64(hi) << int64(32)) | int64(lo) + return (int64(hi) << 32) | int64(lo) @kernel def write64(self, addr: int32, data_high: int32, data_low: int32): @@ -633,8 +633,8 @@ class AD9910: data = int64(self.read64(_AD9910_REG_PROFILE0 + profile)) # Extract and return fields ftw = int32(data) - pow_ = int32(data >> int64(32)) & 0xffff - asf = int32(data >> int64(48)) & 0x3fff + pow_ = int32(data >> 32) & 0xffff + asf = int32(data >> 48) & 0x3fff return ftw, pow_, asf @kernel diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 44b2109cb..651d051c5 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -189,7 +189,7 @@ class AD9912: self.bus.write((AD9912_POW1 << 16) | (3 << 29)) self.bus.set_config_mu(SPI_CONFIG, 32, SPIT_DDS_WR, self.chip_select) - self.bus.write((pow_ << 16) | (int32(ftw >> int64(32)) & 0xffff)) + self.bus.write((pow_ << 16) | (int32(ftw >> 32) & 0xffff)) self.bus.set_config_mu(SPI_CONFIG | SPI_END, 32, SPIT_DDS_WR, self.chip_select) self.bus.write(int32(ftw)) @@ -209,7 +209,7 @@ class AD9912: self.core.break_realtime() # Regain slack to perform second read low = self.read(AD9912_FTW3, 4) # Extract and return fields - ftw = (int64(high & 0xffff) << int64(32)) | (int64(low) & int64(0xffffffff)) + ftw = (int64(high & 0xffff) << 32) | (int64(low) & int64(0xffffffff)) pow_ = (high >> 16) & 0x3fff return ftw, pow_ @@ -219,7 +219,7 @@ class AD9912: frequency. """ return round64(self.ftw_per_hz * frequency) & ( - (int64(1) << int64(48)) - int64(1)) + (int64(1) << 48) - int64(1)) @portable def ftw_to_frequency(self, ftw: int64) -> float: diff --git a/artiq/coredevice/adf5356.py b/artiq/coredevice/adf5356.py index 8376997b6..11af0d6a0 100644 --- a/artiq/coredevice/adf5356.py +++ b/artiq/coredevice/adf5356.py @@ -201,7 +201,7 @@ class ADF5356: # select minimal output divider rf_div_sel = 0 while freq < ADF5356_MIN_VCO_FREQ: - freq <<= int64(1) + freq <<= 1 rf_div_sel += 1 if (1 << rf_div_sel) > 64: @@ -274,7 +274,7 @@ class ADF5356: # calculate PLL at f_pfd/2 n, frac1, (frac2_msb, frac2_lsb), (mod2_msb, mod2_lsb) = calculate_pll( - self.f_vco(), f_pfd >> int64(1) + self.f_vco(), f_pfd >> 1 ) self.core.delay(200. * us) # Slack @@ -596,8 +596,8 @@ def calculate_pll(f_vco: int64, f_pfd: int64) -> tuple[int32, int32, tuple[int32 mod2 = f_pfd while mod2 > int64(ADF5356_MAX_MODULUS2): - mod2 >>= int64(1) - frac2 >>= int64(1) + mod2 >>= 1 + frac2 >>= 1 gcd_div = gcd(frac2, mod2) mod2 //= gcd_div diff --git a/artiq/coredevice/shuttler.py b/artiq/coredevice/shuttler.py index cc75dc9b0..a9d8596ef 100644 --- a/artiq/coredevice/shuttler.py +++ b/artiq/coredevice/shuttler.py @@ -176,11 +176,11 @@ class DCBias: a1, a1 >> 16, int32(a2 & int64(0xFFFF)), - int32((a2 >> int64(16)) & int64(0xFFFF)), - int32((a2 >> int64(32)) & int64(0xFFFF)), + int32((a2 >> 16) & int64(0xFFFF)), + int32((a2 >> 32) & int64(0xFFFF)), int32(a3 & int64(0xFFFF)), - int32((a3 >> int64(16)) & int64(0xFFFF)), - int32((a3 >> int64(32)) & int64(0xFFFF)), + int32((a3 >> 16) & int64(0xFFFF)), + int32((a3 >> 32) & int64(0xFFFF)), ] for i in range(len(coef_words)): @@ -269,11 +269,11 @@ class DDS: b1, b1 >> 16, int32(b2 & int64(0xFFFF)), - int32((b2 >> int64(16)) & int64(0xFFFF)), - int32((b2 >> int64(32)) & int64(0xFFFF)), + int32((b2 >> 16) & int64(0xFFFF)), + int32((b2 >> 32) & int64(0xFFFF)), int32(b3 & int64(0xFFFF)), - int32((b3 >> int64(16)) & int64(0xFFFF)), - int32((b3 >> int64(32)) & int64(0xFFFF)), + int32((b3 >> 16) & int64(0xFFFF)), + int32((b3 >> 32) & int64(0xFFFF)), c0, c1, c1 >> 16, From c3802108ba6222a5b36abee47993f455ae9ce07b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 11 Nov 2023 16:50:26 +0800 Subject: [PATCH 258/352] update NAC3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index a1b80bb7c..972fa9a3f 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1699435769, - "narHash": "sha256-zrtjjYibnO9ukgEEBXAT/3o8vWsFN+IY5zad9sBaLAg=", + "lastModified": 1699672258, + "narHash": "sha256-gZb++0RLKFnxj3RftNTdoX4NedWGM6MQr6MkcCfBmbk=", "ref": "refs/heads/master", - "rev": "1ca4de99b951a50d129b8d07a3d9d896596f1c3c", - "revCount": 927, + "rev": "f020d61cbb3b103182337c9cf57daef35dfa0c4a", + "revCount": 931, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 931b3172c40bc19d5f8b7e47639c61d7b10a5766 Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Fri, 17 Nov 2023 03:49:24 +0800 Subject: [PATCH 259/352] flake: fix vivado on recent nixpkgs (closes #2274) Signed-off-by: Florian Agbuya --- flake.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 509ad62bd..e3804f418 100644 --- a/flake.nix +++ b/flake.nix @@ -173,7 +173,9 @@ vivado = pkgs.buildFHSEnv { name = "vivado"; targetPkgs = vivadoDeps; - profile = "set -e; source /opt/Xilinx/Vivado/2022.2/settings64.sh"; + # Include /usr/lib to FHS env to fix `libtinfo.so.5` not found error + # Path has been removed in https://github.com/NixOS/nixpkgs/pull/263201 + profile = "set -e; source /opt/Xilinx/Vivado/2022.2/settings64.sh; export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH"; runScript = "vivado"; }; From 9f368ee610c8afb0a59139f3e7372d43ff30092c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 25 Nov 2023 14:00:09 +0800 Subject: [PATCH 260/352] update NAC3, switch Windows to CLANG64 and Python 3.11 --- flake.lock | 14 +++++++------- windows/PKGBUILD.artiq | 34 ++++++++++++++++----------------- windows/PKGBUILD.artiq-comtools | 10 +++++----- windows/PKGBUILD.common | 17 +++++++---------- windows/PKGBUILD.sipyco | 8 ++++---- 5 files changed, 40 insertions(+), 43 deletions(-) diff --git a/flake.lock b/flake.lock index 972fa9a3f..f4a396f2d 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1699672258, - "narHash": "sha256-gZb++0RLKFnxj3RftNTdoX4NedWGM6MQr6MkcCfBmbk=", + "lastModified": 1700820685, + "narHash": "sha256-Tir7h8esL4kp+0V9fe0OpC8LQvC8ZQlF9fu0B5QAnfo=", "ref": "refs/heads/master", - "rev": "f020d61cbb3b103182337c9cf57daef35dfa0c4a", - "revCount": 931, + "rev": "fcda360ad63857c2d4a0376e3e0a4dd6c1e77a9e", + "revCount": 937, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,11 +79,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1699343069, - "narHash": "sha256-s7BBhyLA6MI6FuJgs4F/SgpntHBzz40/qV0xLPW6A1Q=", + "lastModified": 1700786208, + "narHash": "sha256-vP0WI7qNkg3teQJN5xjFcxgnBNiKCbkgw3X9HcAxWJY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ec750fd01963ab6b20ee1f0cb488754e8036d89d", + "rev": "8b8c9407844599546393146bfac901290e0ab96b", "type": "github" }, "original": { diff --git a/windows/PKGBUILD.artiq b/windows/PKGBUILD.artiq index c2ae0b99f..d16ee6a1d 100644 --- a/windows/PKGBUILD.artiq +++ b/windows/PKGBUILD.artiq @@ -1,25 +1,25 @@ pkgbase="mingw-w64-artiq" -pkgname="mingw-w64-x86_64-artiq" +pkgname="mingw-w64-clang-x86_64-artiq" pkgrel=1 pkgdesc="A leading-edge control system for quantum information experiments" license=("LGPL") depends=( - "mingw-w64-x86_64-python" - "mingw-w64-x86_64-python-h5py" - "mingw-w64-x86_64-python-lmdb" - "mingw-w64-x86_64-python-pyqt5" - "mingw-w64-x86_64-qt5-svg" - "mingw-w64-x86_64-python-qasync" - "mingw-w64-x86_64-python-pyqtgraph" - "mingw-w64-x86_64-python-numpy" - "mingw-w64-x86_64-python-scipy" - "mingw-w64-x86_64-python-dateutil" - "mingw-w64-x86_64-python-prettytable" - "mingw-w64-x86_64-python-tqdm" - "mingw-w64-x86_64-python-pygit2" - "mingw-w64-x86_64-python-sipyco" - "mingw-w64-x86_64-nac3artiq" - "mingw-w64-x86_64-artiq-comtools" + "mingw-w64-clang-x86_64-python" + "mingw-w64-clang-x86_64-python-h5py" + "mingw-w64-clang-x86_64-python-lmdb" + "mingw-w64-clang-x86_64-python-pyqt5" + "mingw-w64-clang-x86_64-qt5-svg" + "mingw-w64-clang-x86_64-python-qasync" + "mingw-w64-clang-x86_64-python-pyqtgraph" + "mingw-w64-clang-x86_64-python-numpy" + "mingw-w64-clang-x86_64-python-scipy" + "mingw-w64-clang-x86_64-python-dateutil" + "mingw-w64-clang-x86_64-python-prettytable" + "mingw-w64-clang-x86_64-python-tqdm" + "mingw-w64-clang-x86_64-python-pygit2" + "mingw-w64-clang-x86_64-python-sipyco" + "mingw-w64-clang-x86_64-nac3artiq" + "mingw-w64-clang-x86_64-artiq-comtools" ) source PKGBUILD.common diff --git a/windows/PKGBUILD.artiq-comtools b/windows/PKGBUILD.artiq-comtools index 2bd5f3e64..11598c88a 100644 --- a/windows/PKGBUILD.artiq-comtools +++ b/windows/PKGBUILD.artiq-comtools @@ -1,13 +1,13 @@ pkgbase="mingw-w64-artiq-comtools" -pkgname="mingw-w64-x86_64-artiq-comtools" +pkgname="mingw-w64-clang-x86_64-artiq-comtools" pkgrel=1 pkgdesc="Lightweight ARTIQ communication tools" license=("LGPL") depends=( - "mingw-w64-x86_64-python" - "mingw-w64-x86_64-python-sipyco" - "mingw-w64-x86_64-python-numpy" - "mingw-w64-x86_64-python-aiohttp" + "mingw-w64-clang-x86_64-python" + "mingw-w64-clang-x86_64-python-sipyco" + "mingw-w64-clang-x86_64-python-numpy" + "mingw-w64-clang-x86_64-python-aiohttp" ) source PKGBUILD.common diff --git a/windows/PKGBUILD.common b/windows/PKGBUILD.common index 504785679..e8c58f2c7 100644 --- a/windows/PKGBUILD.common +++ b/windows/PKGBUILD.common @@ -1,32 +1,29 @@ arch=("any") -mingw_arch=("mingw64") +mingw_arch=("clang64") pkgver=${DRV_VERSION} url="https://m-labs.hk" source=("source.tar") sha256sums=("SKIP") build() { - mkdir mingw64 - export PYTHONPATH=`pwd`/mingw64/lib/python3.10/site-packages + mkdir clang64 + export PYTHONPATH=`pwd`/clang64/lib/python3.11/site-packages chmod +w -R source cd source - wine-msys2-build python setup.py install --single-version-externally-managed --prefix=../mingw64 --record=setuptools-sucks.txt + wine-msys2-build python setup.py install --single-version-externally-managed --prefix=../clang64 --record=setuptools-sucks.txt cd .. - # setuptools creates this file if it doesn't already exist, which causes conflicts between pacman packages - # see: https://corte.si/posts/code/setuptoolssucks/ - rm -f mingw64/lib/python3.10/site-packages/easy-install.pth # patch broken shebangs (Z:/nix/store/...) - for entrypoint in mingw64/bin/*-script.py; do + for entrypoint in clang64/bin/*-script.py; do [ -f "$entrypoint" ] || continue sed -i "1s|#!.*|#!python|" $entrypoint done - for entrypoint in mingw64/bin/*-script.pyw; do + for entrypoint in clang64/bin/*-script.pyw; do [ -f "$entrypoint" ] || continue sed -i "1s|#!.*|#!pythonw|" $entrypoint done } package() { - cp -R mingw64 ${pkgdir} + cp -R clang64 ${pkgdir} } diff --git a/windows/PKGBUILD.sipyco b/windows/PKGBUILD.sipyco index 7430d590e..ebaa740b4 100644 --- a/windows/PKGBUILD.sipyco +++ b/windows/PKGBUILD.sipyco @@ -1,12 +1,12 @@ pkgbase="mingw-w64-python-sipyco" -pkgname="mingw-w64-x86_64-python-sipyco" +pkgname="mingw-w64-clang-x86_64-python-sipyco" pkgrel=1 pkgdesc="Simple Python Communications" license=("LGPL") depends=( - "mingw-w64-x86_64-python" - "mingw-w64-x86_64-python-numpy" - "mingw-w64-x86_64-python-pybase64" + "mingw-w64-clang-x86_64-python" + "mingw-w64-clang-x86_64-python-numpy" + "mingw-w64-clang-x86_64-python-pybase64" ) source PKGBUILD.common From e831cb47b826c969867b93372f7394a1305e8e7f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 25 Nov 2023 16:14:22 +0800 Subject: [PATCH 261/352] windows: add jsonschema dependency --- windows/PKGBUILD.artiq | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/PKGBUILD.artiq b/windows/PKGBUILD.artiq index d16ee6a1d..48360f8ca 100644 --- a/windows/PKGBUILD.artiq +++ b/windows/PKGBUILD.artiq @@ -18,6 +18,7 @@ depends=( "mingw-w64-clang-x86_64-python-tqdm" "mingw-w64-clang-x86_64-python-pygit2" "mingw-w64-clang-x86_64-python-sipyco" + "mingw-w64-clang-x86_64-python-jsonschema" "mingw-w64-clang-x86_64-nac3artiq" "mingw-w64-clang-x86_64-artiq-comtools" ) From da510919f3a2ef81a882bdf7b6544e5cac83b8f2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 25 Nov 2023 20:16:56 +0800 Subject: [PATCH 262/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index f4a396f2d..b51896e07 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1700820685, - "narHash": "sha256-Tir7h8esL4kp+0V9fe0OpC8LQvC8ZQlF9fu0B5QAnfo=", + "lastModified": 1700914529, + "narHash": "sha256-viy8npVraZV5+LS7GAC6easfP4aWCHvbF9EKhmJJxLE=", "ref": "refs/heads/master", - "rev": "fcda360ad63857c2d4a0376e3e0a4dd6c1e77a9e", - "revCount": 937, + "rev": "cee62aa6c5bd9e365bd9b1a3a893ebac1075159e", + "revCount": 938, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 9a9b3b7858a62dcf2ae04c182331565f82c7fa78 Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Tue, 28 Nov 2023 10:01:03 +0800 Subject: [PATCH 263/352] flake: add new booktabs dependency for artiq-manual-pdf --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index e3804f418..bcbb2349e 100644 --- a/flake.nix +++ b/flake.nix @@ -292,7 +292,7 @@ inherit (pkgs.texlive) scheme-basic latexmk cmap collection-fontsrecommended fncychap titlesec tabulary varwidth framed fancyvrb float wrapfig parskip - upquote capt-of needspace etoolbox; + upquote capt-of needspace etoolbox booktabs; }; in rec { packages.x86_64-linux = rec { From 8c520422f267811840f054b4b707b6b31fd7a677 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 3 Dec 2023 10:27:01 +0800 Subject: [PATCH 264/352] Revert "flake: fix vivado on recent nixpkgs (closes #2274)" This reverts commit 931b3172c40bc19d5f8b7e47639c61d7b10a5766. --- flake.nix | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index bcbb2349e..51e72c917 100644 --- a/flake.nix +++ b/flake.nix @@ -173,9 +173,7 @@ vivado = pkgs.buildFHSEnv { name = "vivado"; targetPkgs = vivadoDeps; - # Include /usr/lib to FHS env to fix `libtinfo.so.5` not found error - # Path has been removed in https://github.com/NixOS/nixpkgs/pull/263201 - profile = "set -e; source /opt/Xilinx/Vivado/2022.2/settings64.sh; export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH"; + profile = "set -e; source /opt/Xilinx/Vivado/2022.2/settings64.sh"; runScript = "vivado"; }; From bd61687e8f2aa3c180aa9937b60fdb8176d2b1b8 Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Tue, 28 Nov 2023 16:54:13 +0800 Subject: [PATCH 265/352] flake: fix ncurses on vivado Signed-off-by: Florian Agbuya --- flake.nix | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 51e72c917..a8cec8731 100644 --- a/flake.nix +++ b/flake.nix @@ -46,9 +46,16 @@ postPatch = "substituteInPlace src/sysroot.rs --replace 2021 2018"; }); - vivadoDeps = pkgs: with pkgs; [ + vivadoDeps = pkgs: with pkgs; let + # Apply patch from https://github.com/nix-community/nix-environments/pull/54 + # to fix ncurses libtinfo.so's soname issue + ncurses' = ncurses5.overrideAttrs (old: { + configureFlags = old.configureFlags ++ [ "--with-termlib" ]; + postFixup = ""; + }); + in [ libxcrypt-legacy - ncurses5 + (ncurses'.override { unicodeSupport = false; }) zlib libuuid xorg.libSM From 985da815ae2dec7fd76c782e5cafb6f231e90408 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 3 Dec 2023 10:37:08 +0800 Subject: [PATCH 266/352] flake: update dependencies --- flake.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/flake.lock b/flake.lock index b51896e07..018cef63f 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1700914529, - "narHash": "sha256-viy8npVraZV5+LS7GAC6easfP4aWCHvbF9EKhmJJxLE=", + "lastModified": 1701570665, + "narHash": "sha256-KZB5Keuzs2nM7cpzx/tTjK5GsVzP5E3AahxWR4vxX64=", "ref": "refs/heads/master", - "rev": "cee62aa6c5bd9e365bd9b1a3a893ebac1075159e", - "revCount": 938, + "rev": "bfa9ceaae3640dbe344cbf56fccd86530892bc69", + "revCount": 940, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,16 +79,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1700786208, - "narHash": "sha256-vP0WI7qNkg3teQJN5xjFcxgnBNiKCbkgw3X9HcAxWJY=", + "lastModified": 1701389149, + "narHash": "sha256-rU1suTIEd5DGCaAXKW6yHoCfR1mnYjOXQFOaH7M23js=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8b8c9407844599546393146bfac901290e0ab96b", + "rev": "5de0b32be6e85dc1a9404c75131316e4ffbc634c", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-unstable", + "ref": "nixos-23.11", "repo": "nixpkgs", "type": "github" } From c618d5daa8a7c0255c027b2c9af5dbc19bef5dae Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Dec 2023 19:38:29 +0800 Subject: [PATCH 267/352] core: add ConstGeneric --- artiq/language/core.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/artiq/language/core.py b/artiq/language/core.py index bcf4a7f8b..00cbae3a3 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -12,7 +12,7 @@ from artiq.language import import_cache __all__ = [ - "Kernel", "KernelInvariant", "virtual", + "Kernel", "KernelInvariant", "virtual", "ConstGeneric", "round64", "floor64", "ceil64", "extern", "kernel", "portable", "nac3", "rpc", "print_rpc", @@ -35,6 +35,12 @@ class KernelInvariant(Generic[T]): class virtual(Generic[T]): pass +class _ConstGenericMarker: + pass + +def ConstGeneric(name, constraint): + return TypeVar(name, _ConstGenericMarker, constraint) + def round64(x): return round(x) From 4c189f8c0576111733bb6ff934035c080c8ccc58 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Dec 2023 09:31:54 +0800 Subject: [PATCH 268/352] core: make _ConstGenericMarker available to NAC3 --- artiq/coredevice/core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index ecd18a429..15bb80a5d 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -4,6 +4,7 @@ from numpy import int32, int64 import nac3artiq from artiq.language.core import * +from artiq.language.core import _ConstGenericMarker # nac3artiq.NAC3 needs to look up this private class from artiq.language import core as core_language from artiq.language.units import * from artiq.language.embedding_map import EmbeddingMap From 089bc1f1681ea44772b622d2cf68c1f1bd46d606 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Dec 2023 10:31:42 +0800 Subject: [PATCH 269/352] flake: update dependencies --- flake.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/flake.lock b/flake.lock index 018cef63f..bfcbf685b 100644 --- a/flake.lock +++ b/flake.lock @@ -12,11 +12,11 @@ ] }, "locked": { - "lastModified": 1693473687, - "narHash": "sha256-BdLddCWbvoEyakcGwhph9b5dIU1iA0hCQV7KYgU8nos=", + "lastModified": 1701573753, + "narHash": "sha256-vhEtXjb9AM6/HnsgfVmhJQeqQ9JqysUm7iWNzTIbexs=", "owner": "m-labs", "repo": "artiq-comtools", - "rev": "f522ef3dbc65961f17b2d3d41e927409d970fd79", + "rev": "199bdabf4de49cb7ada8a4ac7133008e0f8434b7", "type": "github" }, "original": { @@ -30,11 +30,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1692799911, - "narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=", + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", "owner": "numtide", "repo": "flake-utils", - "rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", "type": "github" }, "original": { @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1701570665, - "narHash": "sha256-KZB5Keuzs2nM7cpzx/tTjK5GsVzP5E3AahxWR4vxX64=", + "lastModified": 1702258623, + "narHash": "sha256-Bxe0Z8bWTXTOAQWdc/sI3Yto5IExYVqLDwc15Whu6yU=", "ref": "refs/heads/master", - "rev": "bfa9ceaae3640dbe344cbf56fccd86530892bc69", - "revCount": 940, + "rev": "68556da5fd953c93f17a4aecdc67da80ff58b007", + "revCount": 950, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -111,11 +111,11 @@ ] }, "locked": { - "lastModified": 1697528004, - "narHash": "sha256-FFa2MbhAJEjwY58uOs0swvgymfjubHyWba6Q0X6CbB0=", + "lastModified": 1701572254, + "narHash": "sha256-ixq8dlpyOytDr+d/OmW8v1Ioy9V2G2ibOlNj8GFDSq4=", "owner": "m-labs", "repo": "sipyco", - "rev": "c0a7ed350ccfb85474217057fc47b3f258ca8d99", + "rev": "cceac0df537887135f99aa6b1bdd82853f16b4d6", "type": "github" }, "original": { From 8b4572f9cad34ac0c2b6f6bba9382e7b59b2f93b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Dec 2023 15:54:57 +0800 Subject: [PATCH 270/352] core: pass artiq_builtins to NAC3 --- artiq/coredevice/core.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 15bb80a5d..6aecfd60f 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -4,7 +4,7 @@ from numpy import int32, int64 import nac3artiq from artiq.language.core import * -from artiq.language.core import _ConstGenericMarker # nac3artiq.NAC3 needs to look up this private class +from artiq.language.core import _ConstGenericMarker from artiq.language import core as core_language from artiq.language.units import * from artiq.language.embedding_map import EmbeddingMap @@ -25,6 +25,14 @@ def rtio_get_counter() -> int64: raise NotImplementedError("syscall not simulated") +artiq_builtins = { + "none": none, + "virtual": virtual, + "_ConstGenericMarker": _ConstGenericMarker, + "Option": Option, +} + + @nac3 class Core: """Core device driver. @@ -58,7 +66,7 @@ class Core: self.comm.core = self self.target = target self.analyzed = False - self.compiler = nac3artiq.NAC3(target) + self.compiler = nac3artiq.NAC3(target, artiq_builtins) def close(self): self.comm.close() From 5503c62cd28a89c9812456e1322dc1a40ae856f9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Dec 2023 16:14:35 +0800 Subject: [PATCH 271/352] flake: update dependencies --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index bfcbf685b..5b8838e6d 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1702258623, - "narHash": "sha256-Bxe0Z8bWTXTOAQWdc/sI3Yto5IExYVqLDwc15Whu6yU=", + "lastModified": 1702367868, + "narHash": "sha256-/KHV9SmoWiWMdPkI1rQ8MwDc4HzWqbZzNm5VWYPXrR4=", "ref": "refs/heads/master", - "rev": "68556da5fd953c93f17a4aecdc67da80ff58b007", - "revCount": 950, + "rev": "5bf05c6a6991c98222b50e3e0d6927e8f732eb9e", + "revCount": 967, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 6cb49ac89b340208d3f5c68654010bf1b72ccc7f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 26 Jan 2024 17:11:58 +0800 Subject: [PATCH 272/352] flake: update dependencies --- flake.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/flake.lock b/flake.lock index 5b8838e6d..4ed0b5cd5 100644 --- a/flake.lock +++ b/flake.lock @@ -46,11 +46,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1695805681, - "narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=", + "lastModified": 1704373101, + "narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "6eabade97bc28d707a8b9d82ad13ef143836736e", + "rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2", "type": "github" }, "original": { @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1702367868, - "narHash": "sha256-/KHV9SmoWiWMdPkI1rQ8MwDc4HzWqbZzNm5VWYPXrR4=", + "lastModified": 1706255745, + "narHash": "sha256-3oPouXG+A/LVIZ61ee3nbMpUVYI4mokLwXAzhi2QyZU=", "ref": "refs/heads/master", - "rev": "5bf05c6a6991c98222b50e3e0d6927e8f732eb9e", - "revCount": 967, + "rev": "e328e44c9a6a424d916e628960b1f6eb56cd916f", + "revCount": 1001, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,11 +79,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1701389149, - "narHash": "sha256-rU1suTIEd5DGCaAXKW6yHoCfR1mnYjOXQFOaH7M23js=", + "lastModified": 1706098335, + "narHash": "sha256-r3dWjT8P9/Ah5m5ul4WqIWD8muj5F+/gbCdjiNVBKmU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5de0b32be6e85dc1a9404c75131316e4ffbc634c", + "rev": "a77ab169a83a4175169d78684ddd2e54486ac651", "type": "github" }, "original": { @@ -127,11 +127,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1699335478, - "narHash": "sha256-BsubN4Mfdj02QPK6ZCrl+YOaSg7DaLQdSCVP49ztWik=", + "lastModified": 1702942348, + "narHash": "sha256-gKIfHZxsv+jcgDFRW9mPqmwqbZXuRvXefkZcSFjOGHw=", "owner": "m-labs", "repo": "migen", - "rev": "fd0bf5855a1367eab14b0d6f7f8266178e25d78e", + "rev": "50934ad10a87ade47219b796535978b9bdf24023", "type": "github" }, "original": { From 923ca3377d42c815f979983134ec549dc39d3ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Tue, 20 Feb 2024 13:27:00 +0800 Subject: [PATCH 273/352] cache: can't return list[int32] yet --- artiq/coredevice/cache.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/artiq/coredevice/cache.py b/artiq/coredevice/cache.py index 7db1d0128..3671a5ea4 100644 --- a/artiq/coredevice/cache.py +++ b/artiq/coredevice/cache.py @@ -22,22 +22,23 @@ class CoreCache: def __init__(self, dmgr, core_device="core"): self.core = dmgr.get(core_device) - @kernel - def get(self, key: str) -> list[int32]: - """Extract a value from the core device cache. - After a value is extracted, it cannot be replaced with another value using - :meth:`put` until all kernel functions finish executing; attempting - to replace it will result in a :class:`artiq.coredevice.exceptions.CacheError`. - - If the cache does not contain any value associated with ``key``, an empty list - is returned. - - The value is not copied, so mutating it will change what's stored in the cache. - - :param str key: cache key - :return: a list of 32-bit integers - """ - return cache_get(key) + # NAC3TODO + # @kernel + # def get(self, key: str) -> list[int32]: + # """Extract a value from the core device cache. + # After a value is extracted, it cannot be replaced with another value using + # :meth:`put` until all kernel functions finish executing; attempting + # to replace it will result in a :class:`artiq.coredevice.exceptions.CacheError`. + # + # If the cache does not contain any value associated with ``key``, an empty list + # is returned. + # + # The value is not copied, so mutating it will change what's stored in the cache. + # + # :param str key: cache key + # :return: a list of 32-bit integers + # """ + # return cache_get(key) @kernel def put(self, key: str, value: list[int32]): From 94d3e746021c4e005b9958e760028876f33cd7e1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Feb 2024 13:34:26 +0800 Subject: [PATCH 274/352] flake: update dependencies --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 4ed0b5cd5..f713da204 100644 --- a/flake.lock +++ b/flake.lock @@ -12,11 +12,11 @@ ] }, "locked": { - "lastModified": 1701573753, - "narHash": "sha256-vhEtXjb9AM6/HnsgfVmhJQeqQ9JqysUm7iWNzTIbexs=", + "lastModified": 1707216368, + "narHash": "sha256-ZXoqzG2QsVsybALLYXs473avXcyKSZNh2kIgcPo60XQ=", "owner": "m-labs", "repo": "artiq-comtools", - "rev": "199bdabf4de49cb7ada8a4ac7133008e0f8434b7", + "rev": "e5d0204490bccc07ef9141b0d7c405ab01cb8273", "type": "github" }, "original": { @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1706255745, - "narHash": "sha256-3oPouXG+A/LVIZ61ee3nbMpUVYI4mokLwXAzhi2QyZU=", + "lastModified": 1708407200, + "narHash": "sha256-3btd26JwxP7WI2FDxvaTn5BtXOMT0vxK88SJPK6b1sk=", "ref": "refs/heads/master", - "rev": "e328e44c9a6a424d916e628960b1f6eb56cd916f", - "revCount": 1001, + "rev": "f37de381ce896eebc7aaba1f67b1e2936f20716d", + "revCount": 1016, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,11 +79,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1706098335, - "narHash": "sha256-r3dWjT8P9/Ah5m5ul4WqIWD8muj5F+/gbCdjiNVBKmU=", + "lastModified": 1708294118, + "narHash": "sha256-evZzmLW7qoHXf76VCepvun1esZDxHfVRFUJtumD7L2M=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a77ab169a83a4175169d78684ddd2e54486ac651", + "rev": "e0da498ad77ac8909a980f07eff060862417ccf7", "type": "github" }, "original": { From c1a86f91d3dda672315a49c52d07994e6592650a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 6 Jun 2024 09:47:59 +0800 Subject: [PATCH 275/352] bump major version number --- flake.nix | 2 +- versioneer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index a8cec8731..9cd1ac889 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ pkgs = import nac3.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; }; pkgs-aarch64 = import nac3.inputs.nixpkgs { system = "aarch64-linux"; }; - artiqVersionMajor = 9; + artiqVersionMajor = 10; artiqVersionMinor = self.sourceInfo.revCount or 0; artiqVersionId = self.sourceInfo.shortRev or "unknown"; artiqVersion = (builtins.toString artiqVersionMajor) + "." + (builtins.toString artiqVersionMinor) + "+" + artiqVersionId + ".beta"; diff --git a/versioneer.py b/versioneer.py index eae28b2c6..343e802e4 100644 --- a/versioneer.py +++ b/versioneer.py @@ -11,7 +11,7 @@ def get_rev(): """ def get_version(): - return os.getenv("VERSIONEER_OVERRIDE", default="9.0+unknown.beta") + return os.getenv("VERSIONEER_OVERRIDE", default="10.0+unknown.beta") def get_rev(): return os.getenv("VERSIONEER_REV", default="unknown") From bfbdac0dc2e8ac8c7266e24337b182db9682f34e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 6 Jun 2024 10:01:27 +0800 Subject: [PATCH 276/352] flake: update dependencies --- flake.lock | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/flake.lock b/flake.lock index f713da204..6b864756b 100644 --- a/flake.lock +++ b/flake.lock @@ -12,11 +12,11 @@ ] }, "locked": { - "lastModified": 1707216368, - "narHash": "sha256-ZXoqzG2QsVsybALLYXs473avXcyKSZNh2kIgcPo60XQ=", + "lastModified": 1717637438, + "narHash": "sha256-BXFidNm3Em8iChPGu1L0s2bY+f2yQ0VVid4MuOoTehw=", "owner": "m-labs", "repo": "artiq-comtools", - "rev": "e5d0204490bccc07ef9141b0d7c405ab01cb8273", + "rev": "78d27026efe76a13f7b4698a554f55811369ec4d", "type": "github" }, "original": { @@ -30,11 +30,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1708407200, - "narHash": "sha256-3btd26JwxP7WI2FDxvaTn5BtXOMT0vxK88SJPK6b1sk=", + "lastModified": 1717572602, + "narHash": "sha256-cPBFDZzLdGH+IuoxZcQsGf6srNjxKDesGxfqHNAkO6E=", "ref": "refs/heads/master", - "rev": "f37de381ce896eebc7aaba1f67b1e2936f20716d", - "revCount": 1016, + "rev": "08129cc635c7dea97f7ce9f303e8ad2baad997b7", + "revCount": 1106, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,16 +79,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1708294118, - "narHash": "sha256-evZzmLW7qoHXf76VCepvun1esZDxHfVRFUJtumD7L2M=", + "lastModified": 1717196966, + "narHash": "sha256-yZKhxVIKd2lsbOqYd5iDoUIwsRZFqE87smE2Vzf6Ck0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e0da498ad77ac8909a980f07eff060862417ccf7", + "rev": "57610d2f8f0937f39dbd72251e9614b1561942d8", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.11", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } @@ -111,11 +111,11 @@ ] }, "locked": { - "lastModified": 1701572254, - "narHash": "sha256-ixq8dlpyOytDr+d/OmW8v1Ioy9V2G2ibOlNj8GFDSq4=", + "lastModified": 1717637367, + "narHash": "sha256-4mSm9wl5EMgzzrW6w86IDUevkEOT99FESHGcxcyQbD0=", "owner": "m-labs", "repo": "sipyco", - "rev": "cceac0df537887135f99aa6b1bdd82853f16b4d6", + "rev": "02b96ec2473a3c3d3c980899de2564ddce949dab", "type": "github" }, "original": { @@ -127,11 +127,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1702942348, - "narHash": "sha256-gKIfHZxsv+jcgDFRW9mPqmwqbZXuRvXefkZcSFjOGHw=", + "lastModified": 1715484909, + "narHash": "sha256-4DCHBUBfc/VA+7NW2Hr0+JP4NnKPru2uVJyZjCCk0Ws=", "owner": "m-labs", "repo": "migen", - "rev": "50934ad10a87ade47219b796535978b9bdf24023", + "rev": "4790bb577681a8c3a8d226bc196a4e5deb39e4df", "type": "github" }, "original": { @@ -143,11 +143,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1699352904, - "narHash": "sha256-SglyTmXOPv8jJOjwAjJrj/WhAkItQfUbvKfUqrynwRg=", + "lastModified": 1715647536, + "narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=", "ref": "refs/heads/master", - "rev": "a53859f2167c31ab5225b6c09f30cf05527b94f4", - "revCount": 2452, + "rev": "fea9de558c730bc394a5936094ae95bb9d6fa726", + "revCount": 2455, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From 1a1aa07019145de16833327be8c5afa855c18135 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Thu, 16 May 2024 15:44:25 +0800 Subject: [PATCH 277/352] remove cargo-xbuild, fix nix build --- artiq/firmware/Cargo.lock | 229 +++++++++++++++++++++++++-- artiq/firmware/bootloader/Cargo.toml | 19 ++- artiq/firmware/bootloader/Makefile | 2 - artiq/firmware/ksupport/Makefile | 2 - artiq/firmware/libboard_misoc/lib.rs | 1 + artiq/firmware/libeh/Cargo.toml | 3 +- artiq/firmware/runtime/Cargo.toml | 2 +- artiq/firmware/runtime/Makefile | 2 - artiq/firmware/satman/Makefile | 2 - flake.nix | 7 - 10 files changed, 233 insertions(+), 36 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index f4bd9b88a..01d482c21 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -1,10 +1,42 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "aho-corasick" -version = "0.7.18" +name = "addr2line" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" +dependencies = [ + "cpp_demangle", + "fallible-iterator", + "gimli", + "object", + "rustc-demangle", + "smallvec", +] + +[[package]] +name = "adler" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0453232ace82dee0dd0b4c87a59bd90f7b53b314f3e0f61fe2ee7c8a16482289" + +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" dependencies = [ "memchr", ] @@ -24,9 +56,9 @@ dependencies = [ [[package]] name = "bit_field" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitflags" @@ -66,12 +98,26 @@ dependencies = [ name = "bootloader" version = "0.0.0" dependencies = [ + "addr2line", "board_misoc", "build_misoc", "byteorder", + "cc", + "compiler_builtins", "crc", + "dlmalloc", + "fortanix-sgx-abi", + "getopts", + "hashbrown", + "hermit-abi", + "libc 0.2.79", + "memchr", + "miniz_oxide 0.4.0", "riscv", + "rustc-demangle", "smoltcp", + "unicode-width", + "wasi", ] [[package]] @@ -92,9 +138,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.70" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" +checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c" [[package]] name = "cfg-if" @@ -114,6 +160,15 @@ version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3748f82c7d366a0b4950257d19db685d4958d2fa27c6d164a3f069fec42b748b" +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "crc" version = "1.8.1" @@ -123,12 +178,30 @@ dependencies = [ "build_const", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "cslice" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" +[[package]] +name = "dlmalloc" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332570860c2edf2d57914987bf9e24835425f75825086b6ba7d1e6a3e4f1f254" +dependencies = [ + "libc 0.2.79", +] + [[package]] name = "dyld" version = "0.0.0" @@ -137,7 +210,6 @@ version = "0.0.0" name = "eh" version = "0.0.0" dependencies = [ - "compiler_builtins", "cslice", "libc 0.1.0", "unwind", @@ -160,12 +232,71 @@ dependencies = [ "synstructure", ] +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide 0.7.3", +] + +[[package]] +name = "fortanix-sgx-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56c422ef86062869b2d57ae87270608dc5929969dd130a6e248979cf4fb6ca6" + [[package]] name = "fringe" version = "1.2.1" source = "git+https://git.m-labs.hk/M-Labs/libfringe.git?rev=3ecbe5#3ecbe53f7644b18ee46ebd5b2ca12c9cbceec43a" dependencies = [ - "libc 0.2.101", + "libc 0.2.79", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "gimli" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] + +[[package]] +name = "hashbrown" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7" +dependencies = [ + "ahash", +] + +[[package]] +name = "hermit-abi" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +dependencies = [ + "libc 0.2.79", ] [[package]] @@ -206,9 +337,9 @@ version = "0.1.0" [[package]] name = "libc" -version = "0.2.101" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" +checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" [[package]] name = "log" @@ -248,9 +379,37 @@ checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" [[package]] name = "memchr" -version = "2.4.1" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "miniz_oxide" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" +dependencies = [ + "adler 0.2.3", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +dependencies = [ + "adler 1.0.2", +] + +[[package]] +name = "object" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" +dependencies = [ + "flate2", + "wasmparser", +] [[package]] name = "proto_artiq" @@ -274,9 +433,9 @@ checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" [[package]] name = "regex" -version = "1.5.4" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" dependencies = [ "aho-corasick", "memchr", @@ -285,9 +444,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "riscv" @@ -335,6 +494,12 @@ dependencies = [ "unwind_backtrace", ] +[[package]] +name = "rustc-demangle" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" + [[package]] name = "rustc_version" version = "0.2.3" @@ -372,6 +537,12 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "smoltcp" version = "0.8.2" @@ -383,6 +554,12 @@ dependencies = [ "managed 0.8.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "syn" version = "0.11.11" @@ -413,6 +590,12 @@ dependencies = [ "syn", ] +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + [[package]] name = "unicode-xid" version = "0.0.4" @@ -434,3 +617,15 @@ dependencies = [ "libc 0.1.0", "unwind", ] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasmparser" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index ac0df1001..58cf68e33 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -13,8 +13,25 @@ path = "main.rs" build_misoc = { path = "../libbuild_misoc" } [dependencies] -byteorder = { version = "1.0", default-features = false } +byteorder = { version = "=1.4.3", default-features = false } crc = { version = "1.7", default-features = false } board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp"] } smoltcp = { version = "0.8.2", default-features = false, features = ["medium-ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp"] } riscv = { version = "0.6.0", features = ["inline-asm"] } + +# insanity required by using cargo build-std over xbuild with nix +[dev-dependencies] +getopts = "=0.2.21" +libc = "=0.2.79" +unicode-width = "=0.1.8" +addr2line = "=0.14.0" +memchr = "=2.3.4" +hashbrown = "=0.9.0" +miniz_oxide = "=0.4.0" +rustc-demangle = "=0.1.18" +hermit-abi = "=0.1.17" +dlmalloc = "=0.2.1" +wasi = "=0.9.0" +fortanix-sgx-abi = "=0.3.3" +cc = "=1.0.60" +compiler_builtins = "=0.1.39" \ No newline at end of file diff --git a/artiq/firmware/bootloader/Makefile b/artiq/firmware/bootloader/Makefile index 82baef3eb..032f6df8c 100644 --- a/artiq/firmware/bootloader/Makefile +++ b/artiq/firmware/bootloader/Makefile @@ -3,8 +3,6 @@ include $(MISOC_DIRECTORY)/software/common.mak RUSTFLAGS += -Cpanic=abort -export XBUILD_SYSROOT_PATH=$(BUILDINC_DIRECTORY)/../sysroot - all:: bootloader.bin .PHONY: $(RUSTOUT)/libbootloader.a diff --git a/artiq/firmware/ksupport/Makefile b/artiq/firmware/ksupport/Makefile index 7a7e26d85..ff73b4b65 100644 --- a/artiq/firmware/ksupport/Makefile +++ b/artiq/firmware/ksupport/Makefile @@ -14,8 +14,6 @@ LDFLAGS += --eh-frame-hdr \ RUSTFLAGS += -Cpanic=unwind -export XBUILD_SYSROOT_PATH=$(BUILDINC_DIRECTORY)/../sysroot - all:: ksupport.elf .PHONY: $(RUSTOUT)/libksupport.a diff --git a/artiq/firmware/libboard_misoc/lib.rs b/artiq/firmware/libboard_misoc/lib.rs index 7ba835dcf..4374a44f9 100644 --- a/artiq/firmware/libboard_misoc/lib.rs +++ b/artiq/firmware/libboard_misoc/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![feature(llvm_asm)] +#![feature(asm)] extern crate byteorder; #[cfg(feature = "log")] diff --git a/artiq/firmware/libeh/Cargo.toml b/artiq/firmware/libeh/Cargo.toml index 6998fcd35..3d6837df0 100644 --- a/artiq/firmware/libeh/Cargo.toml +++ b/artiq/firmware/libeh/Cargo.toml @@ -10,5 +10,4 @@ path = "lib.rs" [dependencies] cslice = { version = "0.3" } libc = { path = "../libc" } -unwind = { path = "../libunwind" } -compiler_builtins = "=0.1.39" # A dependency of alloc, libeh doesn't need it +unwind = { path = "../libunwind" } \ No newline at end of file diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 16477707b..d0223a47c 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -17,7 +17,7 @@ failure = { version = "0.1", default-features = false } failure_derive = { version = "0.1", default-features = false } byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } -log = { version = "0.4", default-features = false } +log = { version = "=0.4.14", default-features = false } managed = { version = "^0.7.1", default-features = false, features = ["alloc", "map"] } dyld = { path = "../libdyld" } eh = { path = "../libeh" } diff --git a/artiq/firmware/runtime/Makefile b/artiq/firmware/runtime/Makefile index 0427d763f..f7914e85d 100644 --- a/artiq/firmware/runtime/Makefile +++ b/artiq/firmware/runtime/Makefile @@ -10,8 +10,6 @@ LDFLAGS += \ RUSTFLAGS += -Cpanic=unwind -export XBUILD_SYSROOT_PATH=$(BUILDINC_DIRECTORY)/../sysroot - all:: runtime.bin runtime.fbi .PHONY: $(RUSTOUT)/libruntime.a diff --git a/artiq/firmware/satman/Makefile b/artiq/firmware/satman/Makefile index 82e65d730..41f1f961a 100644 --- a/artiq/firmware/satman/Makefile +++ b/artiq/firmware/satman/Makefile @@ -5,8 +5,6 @@ LDFLAGS += -L../libbase RUSTFLAGS += -Cpanic=abort -export XBUILD_SYSROOT_PATH=$(BUILDINC_DIRECTORY)/../sysroot - all:: satman.bin satman.fbi .PHONY: $(RUSTOUT)/libsatman.a diff --git a/flake.nix b/flake.nix index 9cd1ac889..9b3fd2c58 100644 --- a/flake.nix +++ b/flake.nix @@ -42,10 +42,6 @@ cargo = rust; }); - cargo-xbuild = pkgs.cargo-xbuild.overrideAttrs(oa: { - postPatch = "substituteInPlace src/sysroot.rs --replace 2021 2018"; - }); - vivadoDeps = pkgs: with pkgs; let # Apply patch from https://github.com/nix-community/nix-environments/pull/54 # to fix ncurses libtinfo.so's soname issue @@ -197,7 +193,6 @@ nativeBuildInputs = [ (pkgs.python3.withPackages(ps: [ migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ps.packaging ])) rust - cargo-xbuild pkgs.llvmPackages_14.clang-unwrapped pkgs.llvm_14 pkgs.lld_14 @@ -372,7 +367,6 @@ buildInputs = [ (packages.x86_64-linux.python3-mimalloc.withPackages(ps: with packages.x86_64-linux; [ migen misoc ps.paramiko microscope ps.packaging ] ++ artiq.propagatedBuildInputs)) rust - cargo-xbuild pkgs.llvmPackages_14.clang-unwrapped pkgs.llvm_14 pkgs.lld_14 @@ -395,7 +389,6 @@ buildInputs = [ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ps.packaging ])) rust - cargo-xbuild pkgs.llvmPackages_14.clang-unwrapped pkgs.llvm_14 pkgs.lld_14 From 84217157dd854a3113537447c322ea19114a9e14 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 20 Jun 2024 11:58:14 +0800 Subject: [PATCH 278/352] flake: update dependencies --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 6b864756b..c95adb1c1 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1717572602, - "narHash": "sha256-cPBFDZzLdGH+IuoxZcQsGf6srNjxKDesGxfqHNAkO6E=", + "lastModified": 1718851435, + "narHash": "sha256-R9azy1jQQg9mv4iHAS7sFsk16xy/qlX+pFmdLqAv8wo=", "ref": "refs/heads/master", - "rev": "08129cc635c7dea97f7ce9f303e8ad2baad997b7", - "revCount": 1106, + "rev": "5b1aa812edacebf9a5c93c479c09f08123403f18", + "revCount": 1149, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,11 +79,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1717196966, - "narHash": "sha256-yZKhxVIKd2lsbOqYd5iDoUIwsRZFqE87smE2Vzf6Ck0=", + "lastModified": 1718530797, + "narHash": "sha256-pup6cYwtgvzDpvpSCFh1TEUjw2zkNpk8iolbKnyFmmU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "57610d2f8f0937f39dbd72251e9614b1561942d8", + "rev": "b60ebf54c15553b393d144357375ea956f89e9a9", "type": "github" }, "original": { From f38a3ab795cc81ec5f9151028d5db5bc65a7d66a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 24 Jun 2024 13:54:47 +0800 Subject: [PATCH 279/352] remove lit tests for legacy compiler --- artiq/test/lit/embedding/annotation_py.py | 34 ------------- artiq/test/lit/embedding/class_same_name.py | 51 ------------------- .../lit/embedding/error_subkernel_annot.py | 15 ------ .../embedding/error_subkernel_annot_return.py | 15 ------ .../lit/embedding/error_tuple_index_assign.py | 15 ------ artiq/test/lit/embedding/index_tuple.py | 16 ------ artiq/test/lit/embedding/mixed_tuple.py | 16 ------ .../lit/embedding/subkernel_message_recv.py | 22 -------- .../lit/embedding/subkernel_message_send.py | 20 -------- artiq/test/lit/embedding/subkernel_no_arg.py | 18 ------- artiq/test/lit/embedding/subkernel_return.py | 22 -------- .../lit/embedding/subkernel_return_none.py | 22 -------- artiq/test/lit/embedding/subkernel_self.py | 25 --------- .../test/lit/embedding/subkernel_self_args.py | 25 --------- .../test/lit/embedding/subkernel_with_arg.py | 18 ------- .../lit/embedding/subkernel_with_opt_arg.py | 21 -------- artiq/test/lit/escape/error_numpy_array.py | 15 ------ artiq/test/lit/escape/error_numpy_full.py | 16 ------ .../test/lit/escape/error_numpy_transpose.py | 17 ------- .../test/lit/inferencer/error_tuple_index.py | 14 ----- artiq/test/lit/integration/tuple_index.py | 22 -------- 21 files changed, 439 deletions(-) delete mode 100644 artiq/test/lit/embedding/annotation_py.py delete mode 100644 artiq/test/lit/embedding/class_same_name.py delete mode 100644 artiq/test/lit/embedding/error_subkernel_annot.py delete mode 100644 artiq/test/lit/embedding/error_subkernel_annot_return.py delete mode 100644 artiq/test/lit/embedding/error_tuple_index_assign.py delete mode 100644 artiq/test/lit/embedding/index_tuple.py delete mode 100644 artiq/test/lit/embedding/mixed_tuple.py delete mode 100644 artiq/test/lit/embedding/subkernel_message_recv.py delete mode 100644 artiq/test/lit/embedding/subkernel_message_send.py delete mode 100644 artiq/test/lit/embedding/subkernel_no_arg.py delete mode 100644 artiq/test/lit/embedding/subkernel_return.py delete mode 100644 artiq/test/lit/embedding/subkernel_return_none.py delete mode 100644 artiq/test/lit/embedding/subkernel_self.py delete mode 100644 artiq/test/lit/embedding/subkernel_self_args.py delete mode 100644 artiq/test/lit/embedding/subkernel_with_arg.py delete mode 100644 artiq/test/lit/embedding/subkernel_with_opt_arg.py delete mode 100644 artiq/test/lit/escape/error_numpy_array.py delete mode 100644 artiq/test/lit/escape/error_numpy_full.py delete mode 100644 artiq/test/lit/escape/error_numpy_transpose.py delete mode 100644 artiq/test/lit/inferencer/error_tuple_index.py delete mode 100644 artiq/test/lit/integration/tuple_index.py diff --git a/artiq/test/lit/embedding/annotation_py.py b/artiq/test/lit/embedding/annotation_py.py deleted file mode 100644 index c790b6914..000000000 --- a/artiq/test/lit/embedding/annotation_py.py +++ /dev/null @@ -1,34 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from typing import List, Tuple - -import numpy as np - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: i64 @_Z13testbench.foozz(i64 %ARG.x, { i1, i32 } %ARG.y) - -@kernel -def foo(x: np.int64, y: np.int32 = 1) -> np.int64: - print(x + y) - return x + y - -# CHECK-L: void @_Z13testbench.barzz() -@kernel -def bar(x: np.int32) -> None: - print(x) - -# CHECK-L: @_Z21testbench.unpack_listzz({ i1, i64 }* nocapture writeonly sret({ i1, i64 }) %.1, { i64*, i32 }* %ARG.xs) -@kernel -def unpack_list(xs: List[np.int64]) -> Tuple[bool, np.int64]: - print(xs) - return (len(xs) == 1, xs[0]) - -@kernel -def entrypoint(): - print(foo(0, 2)) - print(foo(1, 3)) - bar(3) - print(unpack_list([1, 2, 3])) diff --git a/artiq/test/lit/embedding/class_same_name.py b/artiq/test/lit/embedding/class_same_name.py deleted file mode 100644 index 46cf7c16d..000000000 --- a/artiq/test/lit/embedding/class_same_name.py +++ /dev/null @@ -1,51 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * - - -class InnerA: - def __init__(self, val): - self.val = val - - @kernel - def run_once(self): - return self.val - - -class InnerB: - def __init__(self, val): - self.val = val - - @kernel - def run_once(self): - return self.val - - -def make_runner(InnerCls, val): - class Runner: - def __init__(self): - self.inner = InnerCls(val) - - @kernel - def run_once(self): - return self.inner.run_once() - - return Runner() - - -class Parent: - def __init__(self): - self.a = make_runner(InnerA, 1) - self.b = make_runner(InnerB, 42.0) - - @kernel - def run_once(self): - return self.a.run_once() + self.b.run_once() - - -parent = Parent() - - -@kernel -def entrypoint(): - parent.run_once() diff --git a/artiq/test/lit/embedding/error_subkernel_annot.py b/artiq/test/lit/embedding/error_subkernel_annot.py deleted file mode 100644 index 3f4bc1c5c..000000000 --- a/artiq/test/lit/embedding/error_subkernel_annot.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: ${LINE:+2}: error: type annotation for argument 'x', '1', is not an ARTIQ type -@subkernel(destination=1) -def foo(x: 1) -> TNone: - pass - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+1}: note: in subkernel call here - foo() diff --git a/artiq/test/lit/embedding/error_subkernel_annot_return.py b/artiq/test/lit/embedding/error_subkernel_annot_return.py deleted file mode 100644 index 51977ae00..000000000 --- a/artiq/test/lit/embedding/error_subkernel_annot_return.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: ${LINE:+2}: error: type annotation for return type, '1', is not an ARTIQ type -@subkernel(destination=1) -def foo() -> 1: - pass - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+1}: note: in subkernel call here - foo() diff --git a/artiq/test/lit/embedding/error_tuple_index_assign.py b/artiq/test/lit/embedding/error_tuple_index_assign.py deleted file mode 100644 index ffa68a6b6..000000000 --- a/artiq/test/lit/embedding/error_tuple_index_assign.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.language.core import * -from artiq.language.types import * - -@kernel -def modify(x): - # CHECK-L: ${LINE:+1}: error: cannot assign to a tuple element - x[0] = 2 - -@kernel -def entrypoint(): - modify((1, "foo", True)) - modify((2, "bar", False)) diff --git a/artiq/test/lit/embedding/index_tuple.py b/artiq/test/lit/embedding/index_tuple.py deleted file mode 100644 index fced90201..000000000 --- a/artiq/test/lit/embedding/index_tuple.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -# CHECK-L: void @_Z16testbench.unpackzz({ i32, { i8*, i32 }, i1 } %ARG.x) - -@kernel -def unpack(x): - print(x[0]) - -@kernel -def entrypoint(): - unpack((1, "foo", True)) - unpack((2, "bar", False)) diff --git a/artiq/test/lit/embedding/mixed_tuple.py b/artiq/test/lit/embedding/mixed_tuple.py deleted file mode 100644 index aaf947149..000000000 --- a/artiq/test/lit/embedding/mixed_tuple.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding %s - -from artiq.language.core import * -from artiq.language.types import * - -@kernel -def consume_tuple(x: TTuple([TInt32, TBool])): - print(x) - -@kernel -def return_tuple() -> TTuple([TInt32, TBool]): - return (123, False) - -@kernel -def entrypoint(): - consume_tuple(return_tuple()) diff --git a/artiq/test/lit/embedding/subkernel_message_recv.py b/artiq/test/lit/embedding/subkernel_message_recv.py deleted file mode 100644 index 35e094aa6..000000000 --- a/artiq/test/lit/embedding/subkernel_message_recv.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -@kernel -def entrypoint(): - # CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !. - message_pass() - # CHECK-NOT: call void @subkernel_send_message\(i32 ., i1 false, i8 1, i8 1, .*\), !dbg !. - # CHECK: call i8 @subkernel_await_message\(i32 2, i64 -1, { i8\*, i32 }\* nonnull .*, i8 1, i8 1\), !dbg !. - subkernel_recv("message", TInt32) - - -# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr -# CHECK-NOT-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr -# CHECK-L: declare i8 @subkernel_await_message(i32, i64, { i8*, i32 }*, i8, i8) local_unnamed_addr -# CHECK-NOT-L: declare void @subkernel_await_finish(i32, i64) local_unnamed_addr -@subkernel(destination=1) -def message_pass() -> TNone: - subkernel_send(0, "message", 15) diff --git a/artiq/test/lit/embedding/subkernel_message_send.py b/artiq/test/lit/embedding/subkernel_message_send.py deleted file mode 100644 index 3f0f77e35..000000000 --- a/artiq/test/lit/embedding/subkernel_message_send.py +++ /dev/null @@ -1,20 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -@kernel -def entrypoint(): - # CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !. - message_pass() - # CHECK: call void @subkernel_send_message\(i32 2, i1 false, i8 1, i8 1, .*\), !dbg !. - # CHECK-NOT: call i8 @subkernel_await_message\(i32 1, i64 10000, { i8\*, i32 }\* nonnull .*, i8 1, i8 1\), !dbg !. - subkernel_send(1, "message", 15) - - -# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr -# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr -@subkernel(destination=1) -def message_pass() -> TNone: - subkernel_recv("message", TInt32) diff --git a/artiq/test/lit/embedding/subkernel_no_arg.py b/artiq/test/lit/embedding/subkernel_no_arg.py deleted file mode 100644 index 605fbbfaa..000000000 --- a/artiq/test/lit/embedding/subkernel_no_arg.py +++ /dev/null @@ -1,18 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -@kernel -def entrypoint(): - # CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !. - # CHECK-NOT: call void @subkernel_send_message\(.*\), !dbg !. - no_arg() - - -# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr -# CHECK-NOT-L: declare void @subkernel_send_message(i32, i1, i8, { i8*, i32 }*, i8**) local_unnamed_addr -@subkernel(destination=1) -def no_arg() -> TStr: - pass diff --git a/artiq/test/lit/embedding/subkernel_return.py b/artiq/test/lit/embedding/subkernel_return.py deleted file mode 100644 index 3c9d1169a..000000000 --- a/artiq/test/lit/embedding/subkernel_return.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -@kernel -def entrypoint(): - # CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !. - # CHECK-NOT: call void @subkernel_send_message\(.*\), !dbg !. - returning() - # CHECK: call i8 @subkernel_await_message\(i32 1, i64 -1, { i8\*, i32 }\* nonnull .*, i8 1, i8 1\), !dbg !. - # CHECK: call void @subkernel_await_finish\(i32 1, i64 -1\), !dbg !. - subkernel_await(returning) - -# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr -# CHECK-NOT-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr -# CHECK-L: declare i8 @subkernel_await_message(i32, i64, { i8*, i32 }*, i8, i8) local_unnamed_addr -# CHECK-L: declare void @subkernel_await_finish(i32, i64) local_unnamed_addr -@subkernel(destination=1) -def returning() -> TInt32: - return 1 diff --git a/artiq/test/lit/embedding/subkernel_return_none.py b/artiq/test/lit/embedding/subkernel_return_none.py deleted file mode 100644 index a7795f785..000000000 --- a/artiq/test/lit/embedding/subkernel_return_none.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -@kernel -def entrypoint(): - # CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !. - # CHECK-NOT: call void @subkernel_send_message\(.*\), !dbg !. - returning_none() - # CHECK: call void @subkernel_await_finish\(i32 1, i64 -1\), !dbg !. - # CHECK-NOT: call i8 @subkernel_await_message\(i32 1, i64 -1\, .*\), !dbg !. - subkernel_await(returning_none) - -# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr -# CHECK-NOT-L: declare void @subkernel_send_message(i32, i1, i8, { i8*, i32 }*, i8**) local_unnamed_addr -# CHECK-L: declare void @subkernel_await_finish(i32, i64) local_unnamed_addr -# CHECK-NOT-L: declare i8 @subkernel_await_message(i32, i64, { i8*, i32 }*, i8, i8) local_unnamed_addr -@subkernel(destination=1) -def returning_none() -> TNone: - pass diff --git a/artiq/test/lit/embedding/subkernel_self.py b/artiq/test/lit/embedding/subkernel_self.py deleted file mode 100644 index 7bf9cbafd..000000000 --- a/artiq/test/lit/embedding/subkernel_self.py +++ /dev/null @@ -1,25 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -class A: - @subkernel(destination=1) - def sk(self): - pass - - @kernel - def kernel_entrypoint(self): - # CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !. - # CHECK-NOT: call void @subkernel_send_message\(.*\), !dbg !. - self.sk() - -a = A() - -@kernel -def entrypoint(): - a.kernel_entrypoint() - -# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr -# CHECK-NOT-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr diff --git a/artiq/test/lit/embedding/subkernel_self_args.py b/artiq/test/lit/embedding/subkernel_self_args.py deleted file mode 100644 index 5aebed2e9..000000000 --- a/artiq/test/lit/embedding/subkernel_self_args.py +++ /dev/null @@ -1,25 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -class A: - @subkernel(destination=1) - def sk(self, a): - pass - - @kernel - def kernel_entrypoint(self): - # CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !. - # CHECK: call void @subkernel_send_message\(i32 1, i1 false, i8 1, i8 1, .*\), !dbg !. - self.sk(1) - -a = A() - -@kernel -def entrypoint(): - a.kernel_entrypoint() - -# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr -# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr diff --git a/artiq/test/lit/embedding/subkernel_with_arg.py b/artiq/test/lit/embedding/subkernel_with_arg.py deleted file mode 100644 index 114516586..000000000 --- a/artiq/test/lit/embedding/subkernel_with_arg.py +++ /dev/null @@ -1,18 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -@kernel -def entrypoint(): - # CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !. - # CHECK: call void @subkernel_send_message\(i32 ., i1 false, i8 1, i8 1, .*\), !dbg !. - accept_arg(1) - - -# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr -# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr -@subkernel(destination=1) -def accept_arg(arg: TInt32) -> TNone: - pass diff --git a/artiq/test/lit/embedding/subkernel_with_opt_arg.py b/artiq/test/lit/embedding/subkernel_with_opt_arg.py deleted file mode 100644 index fb5cc3df1..000000000 --- a/artiq/test/lit/embedding/subkernel_with_opt_arg.py +++ /dev/null @@ -1,21 +0,0 @@ -# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding +compile %s -# RUN: OutputCheck %s --file-to-check=%t.ll - -from artiq.language.core import * -from artiq.language.types import * - -@kernel -def entrypoint(): - # CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !. - # CHECK: call void @subkernel_send_message\(i32 ., i1 false, i8 1, i8 1, .*\), !dbg !. - accept_arg(1) - # CHECK: call void @subkernel_load_run\(i32 1, i8 1, i1 true\), !dbg !. - # CHECK: call void @subkernel_send_message\(i32 ., i1 false, i8 1, i8 2, .*\), !dbg !. - accept_arg(1, 2) - - -# CHECK-L: declare void @subkernel_load_run(i32, i8, i1) local_unnamed_addr -# CHECK-L: declare void @subkernel_send_message(i32, i1, i8, i8, { i8*, i32 }*, i8**) local_unnamed_addr -@subkernel(destination=1) -def accept_arg(arg_a, arg_b=5) -> TNone: - pass diff --git a/artiq/test/lit/escape/error_numpy_array.py b/artiq/test/lit/escape/error_numpy_array.py deleted file mode 100644 index 1ebdeda81..000000000 --- a/artiq/test/lit/escape/error_numpy_array.py +++ /dev/null @@ -1,15 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.experiment import * -import numpy as np - -@kernel -def a(): - # CHECK-L: ${LINE:+2}: error: cannot return an allocated value that does not live forever - # CHECK-L: ${LINE:+1}: note: ... to this point - return np.array([0, 1]) - -@kernel -def entrypoint(): - a() diff --git a/artiq/test/lit/escape/error_numpy_full.py b/artiq/test/lit/escape/error_numpy_full.py deleted file mode 100644 index 66158d8ca..000000000 --- a/artiq/test/lit/escape/error_numpy_full.py +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.experiment import * -import numpy as np - -@kernel -def a(): - # CHECK-L: ${LINE:+2}: error: cannot return an allocated value that does not live forever - # CHECK-L: ${LINE:+1}: note: ... to this point - return np.full(10, 42.0) - - -@kernel -def entrypoint(): - a() diff --git a/artiq/test/lit/escape/error_numpy_transpose.py b/artiq/test/lit/escape/error_numpy_transpose.py deleted file mode 100644 index e1dc32d51..000000000 --- a/artiq/test/lit/escape/error_numpy_transpose.py +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.experiment import * -import numpy as np - -data = np.array([[0, 1], [2, 3]]) - -@kernel -def a(): - # CHECK-L: ${LINE:+2}: error: cannot return an allocated value that does not live forever - # CHECK-L: ${LINE:+1}: note: ... to this point - return np.transpose(data) - -@kernel -def entrypoint(): - a() diff --git a/artiq/test/lit/inferencer/error_tuple_index.py b/artiq/test/lit/inferencer/error_tuple_index.py deleted file mode 100644 index dd6f2dca9..000000000 --- a/artiq/test/lit/inferencer/error_tuple_index.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -i = 0 -x = (1, "foo", True) - -# CHECK-L: ${LINE:+1}: error: tuples can only be indexed by a constant -x[i] - -# CHECK-L: ${LINE:+1}: error: tuples can only be indexed by a constant -x[0:2] - -# CHECK-L: ${LINE:+1}: error: index 3 is out of range for tuple of size 3 -x[3] diff --git a/artiq/test/lit/integration/tuple_index.py b/artiq/test/lit/integration/tuple_index.py deleted file mode 100644 index 46ebb1428..000000000 --- a/artiq/test/lit/integration/tuple_index.py +++ /dev/null @@ -1,22 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# RUN: %python %s - -# Basic indexing -a = (1, "xyz", True) - -assert a[0] == 1 -assert a[1] == "xyz" -assert a[2] == True - -# Nested indexing -b = (a, 2, (3, "abc", a)) - -assert b[0][0] == 1 -assert b[1] == 2 -assert b[2][2][0] == 1 - -# Usage on the LHS of an assignment -c = (1, 2, [1, 2, 3]) - -c[2][0] = 456 -assert c[2][0] == 456 From 3db8612f127ee2acb9d16907b1b97f674429d52c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 24 Jun 2024 14:08:09 +0800 Subject: [PATCH 280/352] artiq_sinara_tester: compilation fixes --- artiq/frontend/artiq_sinara_tester.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index 5d85db1d2..86843ecc4 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -466,7 +466,7 @@ class SinaraTester(EnvExperiment): pass for ch in almaznys: ch.set(31.5, False, True) - self.core.delay(100*ms) + self.core.delay(100.*ms) ch.set(31.5, False, False) @kernel @@ -836,8 +836,8 @@ class SinaraTester(EnvExperiment): input() @kernel - def setup_shuttler_init(self, relay: ShuttlerRelay, adc: ShuttlerADC, dcbias: ShuttlerDCBias, - dds: ShuttlerDDS, trigger: TTLOut, config: ShuttlerConfig): + def setup_shuttler_init(self, relay: ShuttlerRelay, adc: ShuttlerADC, dcbias: list[ShuttlerDCBias], + dds: list[ShuttlerDDS], trigger: ShuttlerTrigger, config: ShuttlerConfig): self.core.break_realtime() # Reset Shuttler Output Relay relay.init() @@ -852,7 +852,7 @@ class SinaraTester(EnvExperiment): delay_mu(int64(self.core.ref_multiplier)) if adc.read_id() >> 4 != 0x038d: - print("Remote AFE Board's ADC is not found. Check Remote AFE Board's Cables Connections") + print_rpc("Remote AFE Board's ADC is not found. Check Remote AFE Board's Cables Connections") assert adc.read_id() >> 4 == 0x038d delay_mu(int64(self.core.ref_multiplier)) @@ -874,21 +874,22 @@ class SinaraTester(EnvExperiment): return adc.read_ch(ch) @kernel - def setup_shuttler_set_output(self, dcbias: ShuttlerDCBias, dds: ShuttlerDDS, trigger: ShuttlerTrigger, ch: int32, volt: float): + def setup_shuttler_set_output(self, dcbias: list[ShuttlerDCBias], dds: list[ShuttlerDDS], + trigger: ShuttlerTrigger, ch: int32, volt: float): self.core.break_realtime() dcbias[ch].set_waveform( a0=shuttler_volt_to_mu(volt), a1=0, - a2=0, - a3=0, + a2=int64(0), + a3=int64(0), ) delay_mu(int64(self.core.ref_multiplier)) dds[ch].set_waveform( b0=0, b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=0, c1=0, c2=0, From 1d71d8de9a8122026e9799c1b76f6bafce2e815a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 24 Jun 2024 14:13:30 +0800 Subject: [PATCH 281/352] test_embedding: integer typing fixes --- artiq/test/coredevice/test_embedding.py | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 9883dc67b..c35205e37 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -44,8 +44,8 @@ class RoundtripTest(ExperimentCase): self.assertRoundtrip(numpy.False_) def test_int(self): - self.assertRoundtrip(numpy.int32(42)) - self.assertRoundtrip(numpy.int64(42)) + self.assertRoundtrip(int32(42)) + self.assertRoundtrip(int64(42)) def test_float(self): self.assertRoundtrip(42.0) @@ -66,7 +66,7 @@ class RoundtripTest(ExperimentCase): self.assertRoundtrip([True, False]) def test_int64_list(self): - self.assertRoundtrip([numpy.int64(0), numpy.int64(1)]) + self.assertRoundtrip([int64(0), int64(1)]) def test_object(self): obj = object() @@ -89,12 +89,12 @@ class RoundtripTest(ExperimentCase): def test_array_1d(self): self.assertArrayRoundtrip(numpy.array([True, False])) - self.assertArrayRoundtrip(numpy.array([1, 2, 3], dtype=numpy.int32)) + self.assertArrayRoundtrip(numpy.array([1, 2, 3], dtype=int32)) self.assertArrayRoundtrip(numpy.array([1.0, 2.0, 3.0])) self.assertArrayRoundtrip(numpy.array(["a", "b", "c"])) def test_array_2d(self): - self.assertArrayRoundtrip(numpy.array([[1, 2], [3, 4]], dtype=numpy.int32)) + self.assertArrayRoundtrip(numpy.array([[1, 2], [3, 4]], dtype=int32)) self.assertArrayRoundtrip(numpy.array([[1.0, 2.0], [3.0, 4.0]])) self.assertArrayRoundtrip(numpy.array([["a", "b"], ["c", "d"]])) @@ -226,7 +226,7 @@ class RPCTypesTest(ExperimentCase): class _RPCCalls(EnvExperiment): def build(self): self.setattr_device("core") - self._list_int64 = [numpy.int64(1)] + self._list_int64 = [int64(1)] def args(self, *args) -> int32: return len(args) @@ -268,7 +268,7 @@ class _RPCCalls(EnvExperiment): @kernel def numpy_things(self): - return (numpy.int32(10), numpy.int64(20)) + return (int32(10), int64(20)) @kernel def builtin(self): @@ -297,11 +297,11 @@ class RPCCallsTest(ExperimentCase): self.assertEqual(exp.kwargs2(), 2) self.assertEqual(exp.args1kwargs2(), 2) self.assertEqual(exp.numpy_things(), - (numpy.int32(10), numpy.int64(20))) + (int32(10), int64(20))) # Ensure lists of int64s don't decay to variable-length builtin integers. list_int64 = exp.list_int64() - self.assertEqual(list_int64, [numpy.int64(1)]) - self.assertTrue(isinstance(list_int64[0], numpy.int64)) + self.assertEqual(list_int64, [int64(1)]) + self.assertTrue(isinstance(list_int64[0], int64)) exp.builtin() exp.async_in_try() @@ -393,8 +393,8 @@ class _ListTuple(EnvExperiment): return 2 def get_values(self, base_a, base_b, n) -> tuple[list[int32], list[int32]]: - return [numpy.int32(base_a + i) for i in range(n)], \ - [numpy.int32(base_b + i) for i in range(n)] + return [int32(base_a + i) for i in range(n)], \ + [int32(base_b + i) for i in range(n)] class _NestedTupleList(EnvExperiment): @@ -442,8 +442,8 @@ class ListTupleTest(ExperimentCase): class _ArrayQuoting(EnvExperiment): def build(self): self.setattr_device("core") - self.vec_i32 = numpy.array([0, 1], dtype=numpy.int32) - self.mat_i64 = numpy.array([[0, 1], [2, 3]], dtype=numpy.int64) + self.vec_i32 = numpy.array([0, 1], dtype=int32) + self.mat_i64 = numpy.array([[0, 1], [2, 3]], dtype=int64) self.arr_f64 = numpy.array([[[0.0, 1.0], [2.0, 3.0]], [[4.0, 5.0], [6.0, 7.0]]]) self.strs = numpy.array(["foo", "bar"]) @@ -579,17 +579,17 @@ class NumpyQuotingTest(ExperimentCase): class _IntBoundary(EnvExperiment): def build(self): self.setattr_device("core") - self.int32_min = numpy.iinfo(numpy.int32).min - self.int32_max = numpy.iinfo(numpy.int32).max - self.int64_min = numpy.iinfo(numpy.int64).min - self.int64_max = numpy.iinfo(numpy.int64).max + self.int32_min = numpy.iinfo(int32).min + self.int32_max = numpy.iinfo(int32).max + self.int64_min = numpy.iinfo(int64).min + self.int64_max = numpy.iinfo(int64).max @kernel - def test_int32_bounds(self, min_val: TInt32, max_val: TInt32): + def test_int32_bounds(self, min_val: int32, max_val: int32): return min_val == self.int32_min and max_val == self.int32_max @kernel - def test_int64_bounds(self, min_val: TInt64, max_val: TInt64): + def test_int64_bounds(self, min_val: int64, max_val: int64): return min_val == self.int64_min and max_val == self.int64_max @kernel From c8f95b142ac36966bf6e7026e9211b26231578a7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 2 Jul 2024 12:21:40 +0200 Subject: [PATCH 282/352] flake: update dependencies --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index c95adb1c1..d184fecbc 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1718851435, - "narHash": "sha256-R9azy1jQQg9mv4iHAS7sFsk16xy/qlX+pFmdLqAv8wo=", + "lastModified": 1719560753, + "narHash": "sha256-PvNjqv0whVk0iJMyoRk8bmbeASG+gcjCArmy/Iwbp3I=", "ref": "refs/heads/master", - "rev": "5b1aa812edacebf9a5c93c479c09f08123403f18", - "revCount": 1149, + "rev": "56fa2b6803f12f833e53d2245a27b4c94804df75", + "revCount": 1167, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 5506b9a7cd12e01483ff0e1f1f010b3cf94738ef Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 3 Jul 2024 07:46:24 +0200 Subject: [PATCH 283/352] flake: update dependencies --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index d184fecbc..ad6ea2595 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1719560753, - "narHash": "sha256-PvNjqv0whVk0iJMyoRk8bmbeASG+gcjCArmy/Iwbp3I=", + "lastModified": 1719982994, + "narHash": "sha256-8qF42y9uYvF+6QGceJAJlqSYJ+uX93h2Rks+OVkt4d8=", "ref": "refs/heads/master", - "rev": "56fa2b6803f12f833e53d2245a27b4c94804df75", - "revCount": 1167, + "rev": "0744b938b822ec59619a3c1274f2017411e2c482", + "revCount": 1168, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 0f6113db3ff832ffc024efc13374a7af86c53460 Mon Sep 17 00:00:00 2001 From: abdul124 Date: Fri, 5 Jul 2024 14:47:27 +0800 Subject: [PATCH 284/352] firmware/ksupport: add rint api --- artiq/firmware/ksupport/api.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index e4d7b2482..47b2e5551 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -105,6 +105,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(nextafter), api!(pow), api!(round), + api!(rint), api!(sin), api!(sinh), api!(sqrt), From 536294433dfaf62277ae49610ea8659c658636a2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Jul 2024 00:06:58 +0800 Subject: [PATCH 285/352] update dependencies, Python 3.12 --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index ad6ea2595..9450dab98 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1719982994, - "narHash": "sha256-8qF42y9uYvF+6QGceJAJlqSYJ+uX93h2Rks+OVkt4d8=", + "lastModified": 1720540572, + "narHash": "sha256-surzhIKGFW1UOP0bciDyw72YVvkFO+iUxTDyf7px8/E=", "ref": "refs/heads/master", - "rev": "0744b938b822ec59619a3c1274f2017411e2c482", - "revCount": 1168, + "rev": "d658d9b00e536aa171ae3356f85825c25175543d", + "revCount": 1198, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,11 +79,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1718530797, - "narHash": "sha256-pup6cYwtgvzDpvpSCFh1TEUjw2zkNpk8iolbKnyFmmU=", + "lastModified": 1720418205, + "narHash": "sha256-cPJoFPXU44GlhWg4pUk9oUPqurPlCFZ11ZQPk21GTPU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b60ebf54c15553b393d144357375ea956f89e9a9", + "rev": "655a58a72a6601292512670343087c2d75d859c1", "type": "github" }, "original": { @@ -127,11 +127,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1715484909, - "narHash": "sha256-4DCHBUBfc/VA+7NW2Hr0+JP4NnKPru2uVJyZjCCk0Ws=", + "lastModified": 1720332047, + "narHash": "sha256-FdYVEHVtXHrzPhBqpXOTo9uHQAtuCsDPmAPY8JrfHOY=", "owner": "m-labs", "repo": "migen", - "rev": "4790bb577681a8c3a8d226bc196a4e5deb39e4df", + "rev": "60739a161e64630ce7ba62d1a5bac1252b66c3b9", "type": "github" }, "original": { From 846d0f92497f32e5ebacb682bd0ca9714520c5a6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 12 Jul 2024 10:26:27 +0200 Subject: [PATCH 286/352] flake: update pyqt5 --- flake.nix | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 83e1ad742..339d2c33c 100644 --- a/flake.nix +++ b/flake.nix @@ -14,7 +14,25 @@ outputs = { self, mozilla-overlay, sipyco, nac3, artiq-comtools, src-migen, src-misoc }: let - pkgs = import nac3.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; }; + pkgs = import nac3.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ + (import mozilla-overlay) + (final: prev: { + pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [ + ( + python-final: python-prev: { + pyqt5 = python-prev.pyqt5.overridePythonAttrs (oldAttrs: rec { + version = "5.15.10"; + src = python-prev.fetchPypi { + pname = "PyQt5"; + inherit version; + hash = "sha256-1Gt4BLGxCk/5F1P4ET5bVYDStEYvMiYoji2ESXM0iYo="; + }; + }); + } + ) + ]; + }) + ]; }; pkgs-aarch64 = import nac3.inputs.nixpkgs { system = "aarch64-linux"; }; artiqVersionMajor = 10; From 6501ee073fe0fe8ed86bb4888332ab00c2702778 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 12 Jul 2024 10:59:46 +0200 Subject: [PATCH 287/352] flake: update dependencies --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 9450dab98..51c073943 100644 --- a/flake.lock +++ b/flake.lock @@ -12,11 +12,11 @@ ] }, "locked": { - "lastModified": 1717637438, - "narHash": "sha256-BXFidNm3Em8iChPGu1L0s2bY+f2yQ0VVid4MuOoTehw=", + "lastModified": 1720768567, + "narHash": "sha256-3VoK7o5MtHtbHLrc6Pv+eQWFtaz5Gd/YWyV5TD3c5Ss=", "owner": "m-labs", "repo": "artiq-comtools", - "rev": "78d27026efe76a13f7b4698a554f55811369ec4d", + "rev": "f93570d8f2ed5a3cfb3e1c16ab00f2540551e994", "type": "github" }, "original": { @@ -127,11 +127,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1720332047, - "narHash": "sha256-FdYVEHVtXHrzPhBqpXOTo9uHQAtuCsDPmAPY8JrfHOY=", + "lastModified": 1720774725, + "narHash": "sha256-HMoXw+gkvCa8hAEgXBC7lpmfw2488ekFfLdD3KNQGYU=", "owner": "m-labs", "repo": "migen", - "rev": "60739a161e64630ce7ba62d1a5bac1252b66c3b9", + "rev": "66f596327515f0dc4833158ad66c90fb3032560f", "type": "github" }, "original": { From 205b08a3439e4c65325cc6394d251c70d81fb9e0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 12 Jul 2024 12:59:52 +0200 Subject: [PATCH 288/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 51c073943..898f32177 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1720540572, - "narHash": "sha256-surzhIKGFW1UOP0bciDyw72YVvkFO+iUxTDyf7px8/E=", + "lastModified": 1720781914, + "narHash": "sha256-9or37AKci5+7OEHuCPCwX+vjs9bNWYZwrMNS6qcmiY4=", "ref": "refs/heads/master", - "rev": "d658d9b00e536aa171ae3356f85825c25175543d", - "revCount": 1198, + "rev": "513d30152b19fb210cabcdde66df3d9bd0083aa6", + "revCount": 1202, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From e29223318638c303022571a49556ecddc2ba974c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 12 Jul 2024 13:06:09 +0200 Subject: [PATCH 289/352] use short exception raise syntax in kernels --- artiq/coredevice/fastino.py | 2 +- artiq/coredevice/grabber.py | 4 ++-- artiq/examples/kc705_nist_clock/repository/tdr.py | 2 +- artiq/frontend/artiq_sinara_tester.py | 2 +- artiq/language/core.py | 2 +- artiq/test/coredevice/test_portability.py | 6 +++--- artiq/test/coredevice/test_rtio.py | 8 ++++---- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index c5f297f74..72a6607c2 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -111,7 +111,7 @@ class Fastino: :param addr: Address to read from. :return: The data read. """ - raise NotImplementedError() + raise NotImplementedError # rtio_output(self.channel | addr | 0x80) # return rtio_input_data(self.channel >> 8) diff --git a/artiq/coredevice/grabber.py b/artiq/coredevice/grabber.py index d57db347b..cc254cf08 100644 --- a/artiq/coredevice/grabber.py +++ b/artiq/coredevice/grabber.py @@ -118,12 +118,12 @@ class Grabber: if timestamp == int64(-1): raise GrabberTimeoutException("Timeout before Grabber frame available") if sentinel != self.sentinel: - raise OutOfSyncException() + raise OutOfSyncException for i in range(len(data)): timestamp, roi_output = rtio_input_timestamped_data(timeout_mu, channel) if roi_output == self.sentinel: - raise OutOfSyncException() + raise OutOfSyncException if timestamp == int64(-1): raise GrabberTimeoutException( "Timeout retrieving ROIs (attempting to read more ROIs than enabled?)") diff --git a/artiq/examples/kc705_nist_clock/repository/tdr.py b/artiq/examples/kc705_nist_clock/repository/tdr.py index fa0776371..0a7380e14 100644 --- a/artiq/examples/kc705_nist_clock/repository/tdr.py +++ b/artiq/examples/kc705_nist_clock/repository/tdr.py @@ -81,6 +81,6 @@ class TDR(EnvExperiment): for i in range(len(self.t)): ti = self.ttl3.timestamp_mu(now_mu()) if ti <= int64(0): - raise PulseNotReceivedError() + raise PulseNotReceivedError self.t[i] = int32(int64(self.t[i]) + ti - t0) self.ttl3.count(now_mu()) # flush diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index 86843ecc4..f0c5d27a7 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -689,7 +689,7 @@ class SinaraTester(EnvExperiment): window=0x000, profiles=[1 for _ in range(len(osc))]) self.core.delay(1.*ms) else: - raise ValueError() + raise ValueError @kernel def phaser_led_wave(self, phasers: list[Phaser]): diff --git a/artiq/language/core.py b/artiq/language/core.py index 00cbae3a3..fd1818e3d 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -138,7 +138,7 @@ class Option(Generic[T]): def unwrap(self): if self.is_none(): - raise UnwrapNoneError() + raise UnwrapNoneError return self._nac3_option def __repr__(self) -> str: diff --git a/artiq/test/coredevice/test_portability.py b/artiq/test/coredevice/test_portability.py index 21f73000a..05988fcb2 100644 --- a/artiq/test/coredevice/test_portability.py +++ b/artiq/test/coredevice/test_portability.py @@ -140,7 +140,7 @@ class _NestedFinally(EnvExperiment): raise ValueError finally: try: - raise IndexError() + raise IndexError except ValueError: self._trace(0) except: @@ -166,7 +166,7 @@ class _NestedExceptions(EnvExperiment): raise finally: try: - raise IndexError() + raise IndexError except ValueError: self._trace(1) raise @@ -212,7 +212,7 @@ class _Exceptions(EnvExperiment): if i == 1: raise _MyException() elif i == 2: - raise IndexError() + raise IndexError except IndexError: self._trace(101) raise diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 6c9969399..90024c15a 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -72,7 +72,7 @@ class RTT(EnvExperiment): self.ttl_inout.pulse(1*us) t1 = self.ttl_inout.timestamp_mu(now_mu()) if t1 < 0: - raise PulseNotReceived() + raise PulseNotReceived self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0)) @@ -96,7 +96,7 @@ class Loopback(EnvExperiment): self.loop_out.pulse(1*us) t1 = self.loop_in.timestamp_mu(now_mu()) if t1 < 0: - raise PulseNotReceived() + raise PulseNotReceived self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0)) @@ -257,7 +257,7 @@ class LoopbackGateTiming(EnvExperiment): in_mu = self.loop_in.timestamp_mu(gate_end_mu) print("timings: ", gate_start_mu, in_mu - lat_offset, gate_end_mu) if in_mu < 0: - raise PulseNotReceived() + raise PulseNotReceived if not (gate_start_mu <= (in_mu - lat_offset) <= gate_end_mu): raise IncorrectPulseTiming("Input event should occur during gate") if not (-2 < (in_mu - out_mu - loop_delay_mu) < 2): @@ -433,7 +433,7 @@ class HandoverException(EnvExperiment): def k(self, var): self.set_dataset(var, now_mu()) delay_mu(1234) - raise DummyException() + raise DummyException def run(self): try: From e7fa28e0a2ed85dbdd9ff81be79688f323c2bbc6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 12 Jul 2024 13:28:32 +0200 Subject: [PATCH 290/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 898f32177..2036a76c9 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1720781914, - "narHash": "sha256-9or37AKci5+7OEHuCPCwX+vjs9bNWYZwrMNS6qcmiY4=", + "lastModified": 1720783672, + "narHash": "sha256-xEwq55fjMldKWYy7DaVgpVhznkKPKHdxYAlq4W0rNRM=", "ref": "refs/heads/master", - "rev": "513d30152b19fb210cabcdde66df3d9bd0083aa6", - "revCount": 1202, + "rev": "c80378063af71ecac53ca3e7e60e728a5c64f37b", + "revCount": 1203, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From d59bded1dd6fc93ba269cec7f23765e25ff5be7e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 21 Jul 2024 13:06:47 +0800 Subject: [PATCH 291/352] flake: update NAC3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 2036a76c9..d7786a707 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1720783672, - "narHash": "sha256-xEwq55fjMldKWYy7DaVgpVhznkKPKHdxYAlq4W0rNRM=", + "lastModified": 1721530825, + "narHash": "sha256-Izm9cbLSTFUiYLkGG1zePjYI+KBS1NK47QIr3Oc1h/Q=", "ref": "refs/heads/master", - "rev": "c80378063af71ecac53ca3e7e60e728a5c64f37b", - "revCount": 1203, + "rev": "7632d6f72ad6031ff123ddb14e1da43f63da5987", + "revCount": 1210, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 2d7bdce3b865adf32ba789bbf6501def4295f885 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 27 Jul 2024 22:21:14 +0800 Subject: [PATCH 292/352] Revert "flake: update pyqt5" This reverts commit 846d0f92497f32e5ebacb682bd0ca9714520c5a6. --- flake.nix | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/flake.nix b/flake.nix index 339d2c33c..83e1ad742 100644 --- a/flake.nix +++ b/flake.nix @@ -14,25 +14,7 @@ outputs = { self, mozilla-overlay, sipyco, nac3, artiq-comtools, src-migen, src-misoc }: let - pkgs = import nac3.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ - (import mozilla-overlay) - (final: prev: { - pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [ - ( - python-final: python-prev: { - pyqt5 = python-prev.pyqt5.overridePythonAttrs (oldAttrs: rec { - version = "5.15.10"; - src = python-prev.fetchPypi { - pname = "PyQt5"; - inherit version; - hash = "sha256-1Gt4BLGxCk/5F1P4ET5bVYDStEYvMiYoji2ESXM0iYo="; - }; - }); - } - ) - ]; - }) - ]; }; + pkgs = import nac3.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; }; pkgs-aarch64 = import nac3.inputs.nixpkgs { system = "aarch64-linux"; }; artiqVersionMajor = 10; From e93d4aa183df76173c9016891cb5ea97058f4e66 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 27 Jul 2024 22:26:05 +0800 Subject: [PATCH 293/352] flake: update dependencies --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index d7786a707..0bec1da5a 100644 --- a/flake.lock +++ b/flake.lock @@ -64,11 +64,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1721530825, - "narHash": "sha256-Izm9cbLSTFUiYLkGG1zePjYI+KBS1NK47QIr3Oc1h/Q=", + "lastModified": 1722090296, + "narHash": "sha256-I4ZW7h6gPlCmV5nLJRQFVhoCob+rx/iExbxKlnXovWM=", "ref": "refs/heads/master", - "rev": "7632d6f72ad6031ff123ddb14e1da43f63da5987", - "revCount": 1210, + "rev": "665ca8e32de99933cf453221b63ffe826a6091f1", + "revCount": 1229, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -79,11 +79,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1720418205, - "narHash": "sha256-cPJoFPXU44GlhWg4pUk9oUPqurPlCFZ11ZQPk21GTPU=", + "lastModified": 1721924956, + "narHash": "sha256-Sb1jlyRO+N8jBXEX9Pg9Z1Qb8Bw9QyOgLDNMEpmjZ2M=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "655a58a72a6601292512670343087c2d75d859c1", + "rev": "5ad6a14c6bf098e98800b091668718c336effc95", "type": "github" }, "original": { @@ -127,11 +127,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1720774725, - "narHash": "sha256-HMoXw+gkvCa8hAEgXBC7lpmfw2488ekFfLdD3KNQGYU=", + "lastModified": 1721561053, + "narHash": "sha256-z3LRhNmKZrjr6rFD0yxtccSa/SWvFIYmb+G/D5d2Jd8=", "owner": "m-labs", "repo": "migen", - "rev": "66f596327515f0dc4833158ad66c90fb3032560f", + "rev": "9279e8623f8433bc4f23ac51e5e2331bfe544417", "type": "github" }, "original": { From c04b0797e0f00b31841bd423419de5f60adeee13 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 27 Jul 2024 23:33:35 +0800 Subject: [PATCH 294/352] msys2: qt6 --- windows/PKGBUILD.artiq | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/PKGBUILD.artiq b/windows/PKGBUILD.artiq index 48360f8ca..012767bdb 100644 --- a/windows/PKGBUILD.artiq +++ b/windows/PKGBUILD.artiq @@ -7,8 +7,8 @@ depends=( "mingw-w64-clang-x86_64-python" "mingw-w64-clang-x86_64-python-h5py" "mingw-w64-clang-x86_64-python-lmdb" - "mingw-w64-clang-x86_64-python-pyqt5" - "mingw-w64-clang-x86_64-qt5-svg" + "mingw-w64-clang-x86_64-python-pyqt6" + "mingw-w64-clang-x86_64-qt6-svg" "mingw-w64-clang-x86_64-python-qasync" "mingw-w64-clang-x86_64-python-pyqtgraph" "mingw-w64-clang-x86_64-python-numpy" From e8544ca094394b63aec2caf2cfd7e7a8c6c202c3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 14 Aug 2024 10:44:30 +0800 Subject: [PATCH 295/352] flake: update dependencies --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 0d54b9d2b..79fd76ed3 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1722090296, - "narHash": "sha256-I4ZW7h6gPlCmV5nLJRQFVhoCob+rx/iExbxKlnXovWM=", + "lastModified": 1723599008, + "narHash": "sha256-HLj4bs8LU3kKY0zuSvOSNKrC2Sc8sB9O//JFvsODTfo=", "ref": "refs/heads/master", - "rev": "665ca8e32de99933cf453221b63ffe826a6091f1", - "revCount": 1229, + "rev": "69320a6cf1445e8fde28537823a26a361f4eb938", + "revCount": 1278, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -95,11 +95,11 @@ ] }, "locked": { - "lastModified": 1722046723, - "narHash": "sha256-G7/gHz8ORRvHd1/RIURrdcswKRPe9K0FsIYR4v5jSWo=", + "lastModified": 1723602049, + "narHash": "sha256-Z/noCSn9WPkv7O77dWKLcBxe4Ub4bWyNzsL5JhjaQfw=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "56baac5e6b2743d4730e664ea64f6d8a2aad0fbb", + "rev": "ea0bf33a11a26a62c60123c49d96011da396602c", "type": "github" }, "original": { From 2f76ac4de61d24669b7a29d68a6e1cb125cf354f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 14 Aug 2024 16:51:07 +0800 Subject: [PATCH 296/352] flake: fix rust installation --- flake.lock | 7 ++++--- flake.nix | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 79fd76ed3..a281fda59 100644 --- a/flake.lock +++ b/flake.lock @@ -95,15 +95,16 @@ ] }, "locked": { - "lastModified": 1723602049, - "narHash": "sha256-Z/noCSn9WPkv7O77dWKLcBxe4Ub4bWyNzsL5JhjaQfw=", + "lastModified": 1719454714, + "narHash": "sha256-MojqG0lyUINkEk0b3kM2drsU5vyaF8DFZe/FAlZVOGs=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "ea0bf33a11a26a62c60123c49d96011da396602c", + "rev": "d1c527659cf076ecc4b96a91c702d080b213801e", "type": "github" }, "original": { "owner": "oxalica", + "ref": "snapshot/2024-08-01", "repo": "rust-overlay", "type": "github" } diff --git a/flake.nix b/flake.nix index 076f3353e..577fb3009 100644 --- a/flake.nix +++ b/flake.nix @@ -3,7 +3,7 @@ inputs.nac3 = { type = "git"; url = "https://git.m-labs.hk/m-labs/nac3.git"; }; inputs.rust-overlay = { - url = "github:oxalica/rust-overlay"; + url = "github:oxalica/rust-overlay?ref=snapshot/2024-08-01"; inputs.nixpkgs.follows = "nac3/nixpkgs"; }; inputs.sipyco.url = github:m-labs/sipyco; From eb4e80e0228f10b792ede2d4753fc6a4ca9d55ab Mon Sep 17 00:00:00 2001 From: mwojcik Date: Thu, 18 Jul 2024 09:49:15 +0800 Subject: [PATCH 297/352] core: implement precompile --- artiq/coredevice/core.py | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 53b92b232..92f5f5739 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -1,4 +1,5 @@ import os, sys, tempfile, subprocess, io +from functools import wraps from numpy import int32, int64 import nac3artiq @@ -117,6 +118,9 @@ class Core: embedding_map = EmbeddingMap() kernel_library = self.compile(function, args, kwargs, embedding_map) + self._run_compiled(kernel_library, embedding_map) + + def _run_compiled(self, kernel_library, embedding_map): if self.first_run: self.comm.check_system_info() self.first_run = False @@ -127,6 +131,44 @@ class Core: self.comm.run() self.comm.serve(embedding_map, symbolizer) + def precompile(self, function, *args, **kwargs): + """Precompile a kernel and return a callable that executes it on the core device + at a later time. + + Arguments to the kernel are set at compilation time and passed to this function, + as additional positional and keyword arguments. + The returned callable accepts no arguments. + + Precompiled kernels may use RPCs and subkernels. + + Object attributes at the beginning of a precompiled kernel execution have the + values they had at precompilation time. If up-to-date values are required, + use RPC to read them. + Similarly, modified values are not written back, and explicit RPC should be used + to modify host objects. + Carefully review the source code of drivers calls used in precompiled kernels, as + they may rely on host object attributes being transfered between kernel calls. + Examples include code used to control DDS phase, and Urukul RF switch control + via the CPLD register. + + The return value of the callable is the return value of the kernel, if any. + + The callable may be called several times. + """ + if not getattr(function, "__artiq_kernel__"): + raise ValueError("Argument is not a kernel") + + embedding_map = EmbeddingMap() + kernel_library = self.compile(function, args, kwargs, embedding_map) + + @wraps(function) + def run_precompiled(): + # NAC3TODO: support returning values + # https://git.m-labs.hk/M-Labs/nac3/issues/101 + self._run_compiled(kernel_library, embedding_map) + + return run_precompiled + @portable def seconds_to_mu(self, seconds: float) -> int64: """Convert seconds to the corresponding number of machine units From 5ffa6e05224f7f4d748c1440de407a268fc8b49e Mon Sep 17 00:00:00 2001 From: spaqin Date: Tue, 13 Aug 2024 09:28:02 +0200 Subject: [PATCH 298/352] examples: fix precompile example for NAC3 --- .../kc705_nist_clock/repository/precompile.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/artiq/examples/kc705_nist_clock/repository/precompile.py b/artiq/examples/kc705_nist_clock/repository/precompile.py index 2ac981d25..4b264c672 100644 --- a/artiq/examples/kc705_nist_clock/repository/precompile.py +++ b/artiq/examples/kc705_nist_clock/repository/precompile.py @@ -1,20 +1,21 @@ from artiq.experiment import * -# NAC3TODO - +@nac3 class Precompile(EnvExperiment): + hello_str: Kernel[str] + def build(self): self.setattr_device("core") self.hello_str = "hello ARTIQ" def prepare(self): - self.precompiled = self.core.precompile(self.hello, "world") + self.precompiled = self.core.precompile(self.hello, "world") @kernel - def hello(self, arg): - print(self.hello_str, arg) - self.hello_str = "nowriteback" + def hello(self, arg: str): + print_rpc((self.hello_str, arg)) + self.hello_str = "nowriteback" def run(self): self.precompiled() From 8183ed1eb0d676e61ff111a0df5d8f309e72f386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Mon, 19 Aug 2024 22:15:17 +0800 Subject: [PATCH 299/352] test/spi: port to NAC3 --- artiq/test/coredevice/test_spi.py | 35 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/artiq/test/coredevice/test_spi.py b/artiq/test/coredevice/test_spi.py index 02429cf09..e6b38ebcd 100644 --- a/artiq/test/coredevice/test_spi.py +++ b/artiq/test/coredevice/test_spi.py @@ -3,16 +3,21 @@ from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase from artiq.language.core import kernel from artiq.language.units import us -from artiq.coredevice import spi2 as spi +from artiq.coredevice.core import Core +from artiq.coredevice.spi2 import * -_SDCARD_SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | - 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) +_SDCARD_SPI_CONFIG = (0*SPI_OFFLINE | 0*SPI_END | + 0*SPI_INPUT | 0*SPI_CS_POLARITY | + 0*SPI_CLK_POLARITY | 0*SPI_CLK_PHASE | + 0*SPI_LSB_FIRST | 0*SPI_HALF_DUPLEX) +@nac3 class CardTest(EnvExperiment): + core: KernelInvariant[Core] + spi_mmc: KernelInvariant[SPIMaster] + def build(self): self.setattr_device("core") self.setattr_device("spi_mmc") @@ -20,18 +25,18 @@ class CardTest(EnvExperiment): @kernel def run(self): self.core.reset() - delay(1*ms) + self.core.delay(1.*ms) - freq = 1*MHz + freq = 1.*MHz cs = 1 # run a couple of clock cycles with miso high to wake up the card self.spi_mmc.set_config(_SDCARD_SPI_CONFIG, 32, freq, 0) for i in range(10): - self.spi_mmc.write(0xffffffff) - self.spi_mmc.set_config(_SDCARD_SPI_CONFIG | spi.SPI_END, 32, freq, 0) - self.spi_mmc.write(0xffffffff) - delay(200*us) + self.spi_mmc.write(-1) + self.spi_mmc.set_config(_SDCARD_SPI_CONFIG | SPI_END, 32, freq, 0) + self.spi_mmc.write(-1) + self.core.delay(200.*us) self.spi_mmc.set_config(_SDCARD_SPI_CONFIG, 8, freq, cs) self.spi_mmc.write(0x40 << 24) # CMD @@ -39,20 +44,20 @@ class CardTest(EnvExperiment): self.spi_mmc.write(0x00000000) # ARG self.spi_mmc.set_config(_SDCARD_SPI_CONFIG, 8, freq, cs) self.spi_mmc.write(0x95 << 24) # CRC - self.spi_mmc.set_config(_SDCARD_SPI_CONFIG | spi.SPI_INPUT, 8, freq, cs) + self.spi_mmc.set_config(_SDCARD_SPI_CONFIG | SPI_INPUT, 8, freq, cs) idle = False response = 0 for i in range(8): self.spi_mmc.write(0xff << 24) # NCR response = self.spi_mmc.read() - delay(100*us) + self.core.delay(100.*us) if response == 0x01: idle = True break - self.spi_mmc.set_config(_SDCARD_SPI_CONFIG | spi.SPI_END, 8, freq, cs) + self.spi_mmc.set_config(_SDCARD_SPI_CONFIG | SPI_END, 8, freq, cs) self.spi_mmc.write(0xff << 24) if not idle: - print(response) + print_rpc(response) raise ValueError("SD Card did not reply with IDLE") From 745935785f7e7a10a1aced795242df6ef3230c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Mon, 19 Aug 2024 22:16:05 +0800 Subject: [PATCH 300/352] test/edge_counter: partial port to NAC3 --- artiq/test/coredevice/test_edge_counter.py | 39 ++++++++++++++-------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/artiq/test/coredevice/test_edge_counter.py b/artiq/test/coredevice/test_edge_counter.py index 1199af6a5..867976d1e 100644 --- a/artiq/test/coredevice/test_edge_counter.py +++ b/artiq/test/coredevice/test_edge_counter.py @@ -1,43 +1,54 @@ +from numpy import int32, int64 + from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut +from artiq.coredevice.edge_counter import EdgeCounter +@nac3 class EdgeCounterExp(EnvExperiment): + core: KernelInvariant[Core] + loop_in_counter: KernelInvariant[EdgeCounter] + loop_out: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("loop_in_counter") self.setattr_device("loop_out") + # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/461 @kernel - def count_pulse_edges(self, gate_fn): + def count_pulse_edges(self, gate_fn) -> tuple[int32, int32]: self.core.break_realtime() with parallel: with sequential: - delay(5 * us) - self.loop_out.pulse(10 * us) + self.core.delay(5. * us) + self.loop_out.pulse(10. * us) with sequential: - gate_fn(10 * us) - delay(1 * us) - gate_fn(10 * us) + #gate_fn(10. * us) + self.core.delay(1. * us) + #gate_fn(10 * us) return (self.loop_in_counter.fetch_count(), self.loop_in_counter.fetch_count()) @kernel - def timeout_timestamp(self): + def timeout_timestamp(self) -> int64: self.core.break_realtime() timestamp_mu, _ = self.loop_in_counter.fetch_timestamped_count( now_mu()) return timestamp_mu @kernel - def gate_relative_timestamp(self): + def gate_relative_timestamp(self) -> int64: self.core.break_realtime() - gate_end_mu = self.loop_in_counter.gate_rising(1 * us) + gate_end_mu = self.loop_in_counter.gate_rising(1. * us) timestamp_mu, _ = self.loop_in_counter.fetch_timestamped_count() return timestamp_mu - gate_end_mu @kernel - def many_pulses_split(self, num_pulses): + def many_pulses_split(self, num_pulses: int32) -> tuple[int32, int32]: self.core.break_realtime() self.loop_in_counter.set_config( @@ -47,8 +58,8 @@ class EdgeCounterExp(EnvExperiment): reset_to_zero=True) for _ in range(num_pulses): - self.loop_out.pulse(5 * us) - delay(5 * us) + self.loop_out.pulse(5. * us) + self.core.delay(5. * us) self.loop_in_counter.set_config( count_rising=True, @@ -57,8 +68,8 @@ class EdgeCounterExp(EnvExperiment): reset_to_zero=False) for _ in range(num_pulses): - self.loop_out.pulse(5 * us) - delay(5 * us) + self.loop_out.pulse(5. * us) + self.core.delay(5. * us) self.loop_in_counter.set_config( count_rising=False, From ff664666b8615705f7538823fed310007f88f214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Mon, 19 Aug 2024 22:21:08 +0800 Subject: [PATCH 301/352] test/stress: partial port to NAC3 --- artiq/test/coredevice/test_stress.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/artiq/test/coredevice/test_stress.py b/artiq/test/coredevice/test_stress.py index 514a2d8ac..4f2183a41 100644 --- a/artiq/test/coredevice/test_stress.py +++ b/artiq/test/coredevice/test_stress.py @@ -1,23 +1,27 @@ -import os -import time import unittest +from numpy import int32 + from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase +from artiq.coredevice.core import Core - +@nac3 class _Stress(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") - @rpc(flags={"async"}) - def sink(self, data): + # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/182 + @rpc #(flags={"async"}) + def sink(self, data: int32): pass @kernel - def async_rpc(self, n): + def async_rpc(self, n: int32): for _ in range(n): - self.sink(b"") + self.sink(0) class StressTest(ExperimentCase): From 735d28be71ac7839381c7b9fe816b2dcffcf0f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Mon, 19 Aug 2024 23:01:10 +0800 Subject: [PATCH 302/352] coredevice/ad9914: adapt to new binary shift typing --- artiq/coredevice/ad9914.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index 12f6dbafd..bd2b5755c 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -243,9 +243,9 @@ class AD9914: # Enable autoclear phase accumulator and enables OSK. self.write(AD9914_REG_CFR1L, 0x2108) fud_time = now_mu() + int64(2) * self.write_duration_mu - pow -= int32((ref_time_mu - fud_time) * self.sysclk_per_mu * int64(ftw) >> int64(32 - 16)) + pow -= int32((ref_time_mu - fud_time) * self.sysclk_per_mu * int64(ftw) >> (32 - 16)) if phase_mode == PHASE_MODE_TRACKING: - pow += int32(ref_time_mu * self.sysclk_per_mu * int64(ftw) >> int64(32 - 16)) + pow += int32(ref_time_mu * self.sysclk_per_mu * int64(ftw) >> (32 - 16)) self.write(AD9914_REG_POW, pow) self.write(AD9914_REG_ASF, asf) @@ -319,9 +319,9 @@ class AD9914: self.write(AD9914_GPIO, (1 << self.channel) << 1) self.write(AD9914_REG_DRGAL, int32(xftw) & 0xffff) - self.write(AD9914_REG_DRGAH, int32(xftw >> int64(16)) & 0x7fff) - self.write(AD9914_REG_DRGFL, int32(xftw >> int64(31)) & 0xffff) - self.write(AD9914_REG_DRGFH, int32(xftw >> int64(47)) & 0xffff) + self.write(AD9914_REG_DRGAH, int32(xftw >> 16) & 0x7fff) + self.write(AD9914_REG_DRGFL, int32(xftw >> 31) & 0xffff) + self.write(AD9914_REG_DRGFH, int32(xftw >> 47) & 0xffff) self.write(AD9914_REG_ASF, amplitude) self.write(AD9914_FUD, 0) @@ -340,7 +340,7 @@ class AD9914: frequency (extended resolution mode). """ return round64(2.0*float(int64(2)**int64(62))*frequency/self.sysclk) & ( - (int64(1) << int64(63)) - int64(1)) + (int64(1) << 63) - int64(1)) @portable def xftw_to_frequency(self, xftw: int64) -> float: From 854f4845fb6fa0db211406d53f7665e8ec328071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Mon, 19 Aug 2024 23:01:36 +0800 Subject: [PATCH 303/352] test/rtio: port to NAC3 (no DMA) --- artiq/test/coredevice/test_rtio.py | 284 +++++++++++++++++++++-------- 1 file changed, 203 insertions(+), 81 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 90024c15a..1d99c21a2 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -2,7 +2,7 @@ # Copyright (C) 2014, 2015 Robert Jordens import os, unittest -import numpy as np +from numpy import int32, int64 from math import sqrt @@ -10,114 +10,154 @@ from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase from artiq.coredevice import exceptions from artiq.coredevice.core import Core -from artiq.coredevice.ttl import TTLOut +from artiq.coredevice.ttl import TTLOut, TTLInOut, TTLClockGen +from artiq.coredevice.ad9914 import AD9914 from artiq.coredevice.comm_mgmt import CommMgmt from artiq.coredevice.comm_analyzer import (StoppedMessage, OutputMessage, InputMessage, decode_dump, get_analyzer_dump) artiq_low_latency = os.getenv("ARTIQ_LOW_LATENCY") -artiq_in_devel = os.getenv("ARTIQ_IN_DEVEL") +@nac3 class RTIOCounter(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") + @rpc + def report(self, dt: float): + self.set_dataset("dt", dt) + @kernel def run(self): t0 = self.core.get_rtio_counter_mu() t1 = self.core.get_rtio_counter_mu() - self.set_dataset("dt", self.core.mu_to_seconds(t1 - t0)) + self.report(self.core.mu_to_seconds(t1 - t0)) +@nac3 class InvalidCounter(Exception): pass +@nac3 class WaitForRTIOCounter(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") @kernel def run(self): self.core.break_realtime() - target_mu = now_mu() + 10000 + target_mu = now_mu() + int64(10000) self.core.wait_until_mu(target_mu) if self.core.get_rtio_counter_mu() < target_mu: raise InvalidCounter +@nac3 class PulseNotReceived(Exception): pass +@nac3 class RTT(EnvExperiment): + core: KernelInvariant[Core] + ttl_inout: KernelInvariant[TTLInOut] + def build(self): self.setattr_device("core") self.setattr_device("ttl_inout") + @rpc + def report(self, rtt: float): + self.set_dataset("rtt", rtt) + @kernel def run(self): self.core.reset() self.ttl_inout.output() - delay(1*us) - with interleave: + self.core.delay(1.*us) + t0 = int64(0) + with parallel: # make sure not to send two commands into the same RTIO # channel with the same timestamp - self.ttl_inout.gate_rising(5*us) + self.ttl_inout.gate_rising(5.*us) with sequential: - delay(1*us) + self.core.delay(1.*us) t0 = now_mu() - self.ttl_inout.pulse(1*us) + self.ttl_inout.pulse(1.*us) t1 = self.ttl_inout.timestamp_mu(now_mu()) - if t1 < 0: + if t1 < int64(0): raise PulseNotReceived - self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0)) + self.report(self.core.mu_to_seconds(t1 - t0)) +@nac3 class Loopback(EnvExperiment): + core: KernelInvariant[Core] + loop_in: KernelInvariant[TTLInOut] + loop_out: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("loop_in") self.setattr_device("loop_out") + @rpc + def report(self, rtt: float): + self.set_dataset("rtt", rtt) + @kernel def run(self): self.core.reset() self.loop_in.input() self.loop_out.off() - delay(1*us) + self.core.delay(1.*us) + t0 = int64(0) with parallel: - self.loop_in.gate_rising(2*us) + self.loop_in.gate_rising(2.*us) with sequential: - delay(1*us) + self.core.delay(1.*us) t0 = now_mu() - self.loop_out.pulse(1*us) + self.loop_out.pulse(1.*us) t1 = self.loop_in.timestamp_mu(now_mu()) - if t1 < 0: + if t1 < int64(0): raise PulseNotReceived - self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0)) + self.report(self.core.mu_to_seconds(t1 - t0)) +@nac3 class ClockGeneratorLoopback(EnvExperiment): + core: KernelInvariant[Core] + loop_clock_in: KernelInvariant[TTLInOut] + loop_clock_out: KernelInvariant[TTLClockGen] + def build(self): self.setattr_device("core") self.setattr_device("loop_clock_in") self.setattr_device("loop_clock_out") + @rpc + def report(self, count: int32): + self.set_dataset("count", count) + @kernel def run(self): self.core.reset() self.loop_clock_in.input() self.loop_clock_out.stop() - delay(200*us) + self.core.delay(200.*us) with parallel: - self.loop_clock_in.gate_rising(10*us) + self.loop_clock_in.gate_rising(10.*us) with sequential: - delay(200*ns) - self.loop_clock_out.set(1*MHz) - self.set_dataset("count", self.loop_clock_in.count(now_mu())) + self.core.delay(200.*ns) + self.loop_clock_out.set(1.*MHz) + self.report(self.loop_clock_in.count(now_mu())) @nac3 @@ -130,7 +170,7 @@ class PulseRate(EnvExperiment): self.setattr_device("ttl_out") @rpc - def set_pulse_rate(self, pulse_rate: float): + def report(self, pulse_rate: float): self.set_dataset("pulse_rate", pulse_rate) @kernel @@ -148,23 +188,31 @@ class PulseRate(EnvExperiment): self.core.break_realtime() else: i -= 1 - self.set_pulse_rate(self.core.mu_to_seconds(dt)) - + self.report(self.core.mu_to_seconds(dt)) +@nac3 class PulseRateAD9914DDS(EnvExperiment): + core: KernelInvariant[Core] + ad9914dds0: KernelInvariant[AD9914] + ad9914dds1: KernelInvariant[AD9914] + def build(self): self.setattr_device("core") self.setattr_device("ad9914dds0") self.setattr_device("ad9914dds1") + @rpc + def report(self, pulse_rate: float): + self.set_dataset("pulse_rate", pulse_rate) + @kernel def run(self): self.core.reset() - dt = self.core.seconds_to_mu(5*us) - freq = self.ad9914dds0.frequency_to_ftw(100*MHz) + dt = self.core.seconds_to_mu(5.*us) + freq = self.ad9914dds0.frequency_to_ftw(100.*MHz) while True: - delay(10*ms) + self.core.delay(10.*ms) for i in range(1250): try: delay_mu(-self.ad9914dds0.set_duration_mu) @@ -173,22 +221,29 @@ class PulseRateAD9914DDS(EnvExperiment): self.ad9914dds1.set_mu(freq) delay_mu(dt) except RTIOUnderflow: - dt += 100 + dt += int64(100) self.core.break_realtime() break else: - self.set_dataset("pulse_rate", self.core.mu_to_seconds(dt//2)) + self.report(self.core.mu_to_seconds(dt//int64(2))) return +@nac3 class LoopbackCount(EnvExperiment): + core: KernelInvariant[Core] + loop_in: KernelInvariant[TTLInOut] + loop_out: KernelInvariant[TTLOut] + npulses: KernelInvariant[int32] + def build(self, npulses): self.setattr_device("core") self.setattr_device("loop_in") self.setattr_device("loop_out") self.npulses = npulses - def set_count(self, count): + @rpc + def report(self, count: int32): self.set_dataset("count", count) @kernel @@ -196,21 +251,27 @@ class LoopbackCount(EnvExperiment): self.core.reset() self.loop_in.input() self.loop_out.output() - delay(5*us) + self.core.delay(5.*us) with parallel: - self.loop_in.gate_rising(10*us) + self.loop_in.gate_rising(10.*us) with sequential: for i in range(self.npulses): - delay(25*ns) - self.loop_out.pulse(25*ns) - self.set_dataset("count", self.loop_in.count(now_mu())) + self.core.delay(25.*ns) + self.loop_out.pulse(25.*ns) + self.report(self.loop_in.count(now_mu())) +@nac3 class IncorrectPulseTiming(Exception): pass +@nac3 class LoopbackGateTiming(EnvExperiment): + core: KernelInvariant[Core] + loop_in: KernelInvariant[TTLInOut] + loop_out: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("loop_in") @@ -222,19 +283,20 @@ class LoopbackGateTiming(EnvExperiment): self.core.reset() self.loop_in.input() self.loop_out.output() - delay_mu(500) + delay_mu(int64(500)) self.loop_out.off() - delay_mu(5000) + delay_mu(int64(5000)) # Determine loop delay. + out_mu = int64(0) with parallel: - self.loop_in.gate_rising_mu(10000) + self.loop_in.gate_rising_mu(int64(10000)) with sequential: - delay_mu(5000) + delay_mu(int64(5000)) out_mu = now_mu() - self.loop_out.pulse_mu(1000) + self.loop_out.pulse_mu(int64(1000)) in_mu = self.loop_in.timestamp_mu(now_mu()) - if in_mu < 0: + if in_mu < int64(0): raise PulseNotReceived("Cannot determine loop delay") loop_delay_mu = in_mu - out_mu @@ -242,37 +304,46 @@ class LoopbackGateTiming(EnvExperiment): # In the most common configuration, 24 mu == 24 ns == 3 coarse periods, # which should be plenty of slack. # FIXME: ZC706 with NIST_QC2 needs 48ns - hw problem? - delay_mu(10000) + delay_mu(int64(10000)) gate_start_mu = now_mu() - self.loop_in.gate_both_mu(48) # XXX + self.loop_in.gate_both_mu(int64(48)) # XXX gate_end_mu = now_mu() # gateware latency offset between gate and input - lat_offset = 11*8 + lat_offset = int64(11*8) out_mu = gate_start_mu - loop_delay_mu + lat_offset at_mu(out_mu) - self.loop_out.pulse_mu(48) # XXX + self.loop_out.pulse_mu(int64(48)) # XXX in_mu = self.loop_in.timestamp_mu(gate_end_mu) - print("timings: ", gate_start_mu, in_mu - lat_offset, gate_end_mu) - if in_mu < 0: + print_rpc("timings:") + print_rpc(gate_start_mu) + print_rpc(in_mu - lat_offset) + print_rpc(gate_end_mu) + if in_mu < int64(0): raise PulseNotReceived if not (gate_start_mu <= (in_mu - lat_offset) <= gate_end_mu): raise IncorrectPulseTiming("Input event should occur during gate") - if not (-2 < (in_mu - out_mu - loop_delay_mu) < 2): + if not (int64(-2) < (in_mu - out_mu - loop_delay_mu) < int64(2)): raise IncorrectPulseTiming("Loop delay should not change") in_mu = self.loop_in.timestamp_mu(gate_end_mu) - if in_mu > 0: + if in_mu > int64(0): raise IncorrectPulseTiming("Only one pulse should be received") +@nac3 class IncorrectLevel(Exception): pass +@nac3 class Level(EnvExperiment): + core: KernelInvariant[Core] + loop_in: KernelInvariant[TTLInOut] + loop_out: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("loop_in") @@ -283,20 +354,25 @@ class Level(EnvExperiment): self.core.reset() self.loop_in.input() self.loop_out.output() - delay(5*us) + self.core.delay(5.*us) self.loop_out.off() - delay(5*us) - if self.loop_in.sample_get_nonrt(): + self.core.delay(5.*us) + if self.loop_in.sample_get_nonrt() != 0: raise IncorrectLevel self.loop_out.on() - delay(5*us) - if not self.loop_in.sample_get_nonrt(): + self.core.delay(5.*us) + if self.loop_in.sample_get_nonrt() == 0: raise IncorrectLevel +@nac3 class Watch(EnvExperiment): + core: KernelInvariant[Core] + loop_in: KernelInvariant[TTLInOut] + loop_out: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("loop_in") @@ -307,27 +383,31 @@ class Watch(EnvExperiment): self.core.reset() self.loop_in.input() self.loop_out.output() - delay(5*us) + self.core.delay(5.*us) self.loop_out.off() - delay(5*us) + self.core.delay(5.*us) if not self.loop_in.watch_stay_off(): raise IncorrectLevel - delay(10*us) + self.core.delay(10.*us) if not self.loop_in.watch_done(): raise IncorrectLevel - delay(10*us) + self.core.delay(10.*us) if not self.loop_in.watch_stay_off(): raise IncorrectLevel - delay(3*us) + self.core.delay(3.*us) self.loop_out.on() - delay(10*us) + self.core.delay(10.*us) if self.loop_in.watch_done(): raise IncorrectLevel +@nac3 class Underflow(EnvExperiment): + core: KernelInvariant[Core] + ttl_out: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("ttl_out") @@ -336,11 +416,15 @@ class Underflow(EnvExperiment): def run(self): self.core.reset() while True: - delay(25*ns) - self.ttl_out.pulse(25*ns) + self.core.delay(25.*ns) + self.ttl_out.pulse(25.*ns) +@nac3 class SequenceError(EnvExperiment): + core: KernelInvariant[Core] + ttl_out: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("ttl_out") @@ -348,13 +432,17 @@ class SequenceError(EnvExperiment): @kernel def run(self): self.core.reset() - delay(55*256*us) + self.core.delay(55.*256.*us) for _ in range(256): - self.ttl_out.pulse(25*us) - delay(-75*us) + self.ttl_out.pulse(25.*us) + self.core.delay(-75.*us) +@nac3 class Collision(EnvExperiment): + core: KernelInvariant[Core] + ttl_out_serdes: KernelInvariant[TTLOut] + def build(self): self.setattr_device("core") self.setattr_device("ttl_out_serdes") @@ -362,15 +450,19 @@ class Collision(EnvExperiment): @kernel def run(self): self.core.reset() - delay(5*ms) # make sure we won't get underflow + self.core.delay(5.*ms) # make sure we won't get underflow for i in range(16): - self.ttl_out_serdes.pulse_mu(1) - delay_mu(1) + self.ttl_out_serdes.pulse_mu(int64(1)) + delay_mu(int64(1)) while self.core.get_rtio_counter_mu() < now_mu(): pass +@nac3 class AddressCollision(EnvExperiment): + core: KernelInvariant[Core] + loop_in: KernelInvariant[TTLInOut] + def build(self): self.setattr_device("core") self.setattr_device("loop_in") @@ -379,60 +471,89 @@ class AddressCollision(EnvExperiment): def run(self): self.core.reset() self.loop_in.input() - self.loop_in.pulse(10*us) + self.loop_in.pulse(10.*us) while self.core.get_rtio_counter_mu() < now_mu(): pass +@nac3 class TimeKeepsRunning(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") + @rpc + def report(self, time_at_start: int64): + self.set_dataset("time_at_start", time_at_start) + @kernel def run(self): self.core.reset() - self.set_dataset("time_at_start", now_mu()) + self.report(now_mu()) +@nac3 class Handover(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") + @rpc + def report(self, var: str, t: int64): + self.set_dataset(var, t) + @kernel - def k(self, var): - self.set_dataset(var, now_mu()) - delay_mu(1234) + def k(self, var: str): + self.report(var, now_mu()) + delay_mu(int64(1234)) def run(self): self.k("t1") self.k("t2") +@nac3 class Rounding(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") + @rpc + def report(self, delta: int64): + self.set_dataset("delta", delta) + @kernel def run(self): self.core.reset() t1 = now_mu() - delay(8*us) + self.core.delay(8.*us) t2 = now_mu() - self.set_dataset("delta", t2 - t1) + self.report(t2 - t1) +@nac3 class DummyException(Exception): pass +@nac3 class HandoverException(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") + @rpc + def report(self, var: str, t: int64): + self.set_dataset(var, t) + @kernel - def k(self, var): - self.set_dataset(var, now_mu()) - delay_mu(1234) + def k(self, var: str): + self.report(var, now_mu()) + delay_mu(int64(1234)) raise DummyException def run(self): @@ -597,7 +718,7 @@ class _DMA(EnvExperiment): self.setattr_device("core_dma") self.setattr_device("ttl_out") self.trace_name = trace_name - self.delta = np.int64(0) + self.delta = int64(0) @kernel def record(self, for_handle=True): @@ -669,6 +790,7 @@ class _DMA(EnvExperiment): self.core_dma.playback_handle(handle) +@unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/338") class DMATest(ExperimentCase): def test_dma_storage(self): exp = self.create(_DMA) From ee6002263246d656a38d79113a605a74c7125693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Mon, 19 Aug 2024 23:06:57 +0800 Subject: [PATCH 304/352] test/analyzer: rtio_log now supported on NAC3 --- artiq/test/coredevice/test_analyzer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/test/coredevice/test_analyzer.py b/artiq/test/coredevice/test_analyzer.py index 776ee3eef..31e08bce8 100644 --- a/artiq/test/coredevice/test_analyzer.py +++ b/artiq/test/coredevice/test_analyzer.py @@ -50,7 +50,7 @@ class WriteLog(EnvExperiment): @kernel def run(self): self.core.reset() - # NAC3TODO rtio_log("foo", 32) + rtio_log("foo", 32) class AnalyzerTest(ExperimentCase): @@ -79,7 +79,6 @@ class AnalyzerTest(ExperimentCase): abs(input_messages[0].timestamp - input_messages[1].timestamp), 1000, delta=4) - @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/297") def test_rtio_log(self): core_host = self.device_mgr.get_desc("core")["arguments"]["host"] From 1a80384fc73487a0c17ca374a8ad3cb1dfb05154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Mon, 19 Aug 2024 23:53:07 +0800 Subject: [PATCH 305/352] test/embedding: partial port to NAC3 --- artiq/test/coredevice/test_embedding.py | 151 +++++++++++++++++------- 1 file changed, 110 insertions(+), 41 deletions(-) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index c35205e37..29055bb26 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -1,11 +1,14 @@ -import numpy -from numpy import int32, int64 import unittest from time import sleep +from typing import Literal + +import numpy +from numpy import int32, int64, ndarray from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase from artiq.coredevice.comm_kernel import RPCReturnValueError +from artiq.coredevice.core import Core class _Roundtrip(EnvExperiment): @@ -16,7 +19,7 @@ class _Roundtrip(EnvExperiment): def roundtrip(self, obj, fn): fn(obj) - +@unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/461") class RoundtripTest(ExperimentCase): def assertRoundtrip(self, obj): exp = self.create(_Roundtrip) @@ -106,15 +109,20 @@ class RoundtripTest(ExperimentCase): self.assertArrayRoundtrip(numpy.array([[1, 2], [3]], dtype=object)) +@nac3 class _DefaultArg(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") - def test(self, foo=42) -> int32: + @rpc + def test(self, foo: int32 = 42) -> int32: return foo + # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/101 @kernel - def run(self): + def run(self) -> int32: return self.test() @@ -124,46 +132,50 @@ class DefaultArgTest(ExperimentCase): self.assertEqual(exp.run(), 42) +@nac3 class _RPCTypes(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") + @rpc def return_bool(self) -> bool: return True + @rpc def return_int32(self) -> int32: return 1 + @rpc def return_int64(self) -> int64: return 0x100000000 + @rpc def return_float(self) -> float: return 1.0 + @rpc def return_str(self) -> str: return "foo" - def return_bytes(self) -> bytes: - return b"foo" - - def return_bytearray(self) -> bytearray: - return bytearray(b"foo") - + @rpc def return_tuple(self) -> tuple[int32, int32]: return (1, 2) + @rpc def return_list(self) -> list[int32]: return [2, 3] - def return_range(self) -> range: - return range(10) - - def return_array(self) -> numpy.ndarray: # NAC3TODO [int32] + @rpc + def return_array(self) -> ndarray[int32, Literal[1]]: return numpy.array([1, 2]) - def return_matrix(self) -> numpy.ndarray: # NAC3TODO [int32, 2] + @rpc + def return_matrix(self) -> ndarray[int32, Literal[2]]: return numpy.array([[1, 2], [3, 4]]) + @rpc def return_mismatch(self): return b"foo" @@ -174,28 +186,21 @@ class _RPCTypes(EnvExperiment): core_log(self.return_int64()) core_log(self.return_float()) core_log(self.return_str()) - core_log(self.return_bytes()) - core_log(self.return_bytearray()) core_log(self.return_tuple()) core_log(self.return_list()) - core_log(self.return_range()) core_log(self.return_array()) core_log(self.return_matrix()) def accept(self, value): pass - @kernel + # NAC3TODO @kernel def run_send(self): self.accept(True) self.accept(1) self.accept(0x100000000) self.accept(1.0) self.accept("foo") - self.accept(b"foo") - self.accept(bytearray(b"foo")) - self.accept(bytes([1, 2])) - self.accept(bytearray([1, 2])) self.accept((2, 3)) self.accept([1, 2]) self.accept(range(10)) @@ -223,7 +228,10 @@ class RPCTypesTest(ExperimentCase): exp.run_mismatch() +# NAC3TODO class _RPCCalls(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") self._list_int64 = [int64(1)] @@ -306,13 +314,17 @@ class RPCCallsTest(ExperimentCase): exp.async_in_try() +@nac3 class _Annotation(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") + # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/101 @kernel def overflow(self, x: int64) -> bool: - return (x << 32) != 0 + return (x << 32) != int64(0) @kernel def monomorphize(self, x: list[int32]): @@ -322,15 +334,19 @@ class _Annotation(EnvExperiment): class AnnotationTest(ExperimentCase): def test_annotation(self): exp = self.create(_Annotation) - self.assertEqual(exp.overflow(1), True) + self.assertEqual(exp.overflow(int64(1)), True) exp.monomorphize([]) + +@nac3 class _Async(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") - @rpc(flags={"async"}) - def recv_async(self, data): + @rpc # NAC3TODO (flags={"async"}) + def recv_async(self, data: list[int32]): pass @kernel @@ -347,11 +363,15 @@ class AsyncTest(ExperimentCase): exp.run() +@nac3 class _Payload1MB(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") - def devnull(self, d): + @rpc + def devnull(self, d: list[int32]): pass @kernel @@ -366,7 +386,10 @@ class LargePayloadTest(ExperimentCase): exp.run() +@nac3 class _ListTuple(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") @@ -384,25 +407,32 @@ class _ListTuple(EnvExperiment): self.verify(d) @kernel - def verify(self, data): + def verify(self, data: list[int32]): for i in range(len(data)): if data[i] != data[0] + i: raise ValueError + @rpc def get_num_iters(self) -> int32: return 2 - def get_values(self, base_a, base_b, n) -> tuple[list[int32], list[int32]]: + @rpc + def get_values(self, base_a: int32, base_b: int32, n: int32) -> tuple[list[int32], list[int32]]: return [int32(base_a + i) for i in range(n)], \ [int32(base_b + i) for i in range(n)] +@nac3 class _NestedTupleList(EnvExperiment): + core: KernelInvariant[Core] + data: KernelInvariant[list[tuple[int32, list[tuple[str, list[float], list[int32]]]]]] + def build(self): self.setattr_device("core") self.data = [(0x12345678, [("foo", [0.0, 1.0], [2, 3])]), (0x76543210, [("bar", [4.0, 5.0], [6, 7])])] + @rpc def get_data(self) -> list[tuple [int32, list[tuple[str, list[float], list[int32]]]]]: return self.data @@ -414,10 +444,14 @@ class _NestedTupleList(EnvExperiment): raise ValueError +@nac3 class _EmptyList(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") + @rpc def get_empty(self) -> list[int32]: return [] @@ -439,7 +473,14 @@ class ListTupleTest(ExperimentCase): self.create(_EmptyList).run() +@nac3 class _ArrayQuoting(EnvExperiment): + core: KernelInvariant[Core] + vec_i32: KernelInvariant[ndarray[int32, Literal[1]]] + mat_i64: KernelInvariant[ndarray[int64, Literal[2]]] + arr_f64: KernelInvariant[ndarray[float, Literal[3]]] + strs: KernelInvariant[ndarray[str, Literal[1]]] + def build(self): self.setattr_device("core") self.vec_i32 = numpy.array([0, 1], dtype=int32) @@ -453,10 +494,10 @@ class _ArrayQuoting(EnvExperiment): assert self.vec_i32[0] == 0 assert self.vec_i32[1] == 1 - assert self.mat_i64[0, 0] == 0 - assert self.mat_i64[0, 1] == 1 - assert self.mat_i64[1, 0] == 2 - assert self.mat_i64[1, 1] == 3 + assert self.mat_i64[0, 0] == int64(0) + assert self.mat_i64[0, 1] == int64(1) + assert self.mat_i64[1, 0] == int64(2) + assert self.mat_i64[1, 1] == int64(3) assert self.arr_f64[0, 0, 0] == 0.0 assert self.arr_f64[0, 0, 1] == 1.0 @@ -467,8 +508,9 @@ class _ArrayQuoting(EnvExperiment): assert self.arr_f64[1, 1, 0] == 6.0 assert self.arr_f64[1, 1, 1] == 7.0 - assert self.strs[0] == "foo" - assert self.strs[1] == "bar" + # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/421 + #assert self.strs[0] == "foo" + #assert self.strs[1] == "bar" class ArrayQuotingTest(ExperimentCase): @@ -476,16 +518,19 @@ class ArrayQuotingTest(ExperimentCase): self.create(_ArrayQuoting).run() +@nac3 class _Assert(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") @kernel - def check(self, value): + def check(self, value: bool): assert value @kernel - def check_msg(self, value): + def check_msg(self, value: bool): assert value, "foo" @@ -504,7 +549,12 @@ class AssertTest(ExperimentCase): check_fail(lambda: exp.check_msg(False), "foo") +@nac3 class _NumpyBool(EnvExperiment): + core: KernelInvariant[Core] + np_true: KernelInvariant[bool] + np_false: KernelInvariant[bool] + def build(self): self.setattr_device("core") self.np_true = numpy.True_ @@ -524,7 +574,16 @@ class NumpyBoolTest(ExperimentCase): self.create(_NumpyBool).run() +@nac3 class _Alignment(EnvExperiment): + core: KernelInvariant[Core] + a: KernelInvariant[bool] + b: KernelInvariant[float] + c: KernelInvariant[bool] + d: KernelInvariant[bool] + e: KernelInvariant[float] + f: KernelInvariant[bool] + def build(self): self.setattr_device("core") self.a = False @@ -560,14 +619,17 @@ class AlignmentTest(ExperimentCase): self.create(_Alignment).run() +@nac3 class _NumpyQuoting(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") @kernel def run(self): - a = numpy.array([10, 20]) - b = numpy.sqrt(4.0) + a = np_array([10, 20]) + b = np_sqrt(4.0) class NumpyQuotingTest(ExperimentCase): @@ -576,7 +638,14 @@ class NumpyQuotingTest(ExperimentCase): self.create(_NumpyQuoting).run() +@nac3 class _IntBoundary(EnvExperiment): + core: KernelInvariant[Core] + int32_min: KernelInvariant[int32] + int32_max: KernelInvariant[int32] + int64_min: KernelInvariant[int64] + int64_max: KernelInvariant[int64] + def build(self): self.setattr_device("core") self.int32_min = numpy.iinfo(int32).min From f56f0b83e78964a79b7f2527a6c1ce6219111dc6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Aug 2024 23:53:46 +0800 Subject: [PATCH 306/352] flake: update dependencies --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index a281fda59..0e685d397 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1723599008, - "narHash": "sha256-HLj4bs8LU3kKY0zuSvOSNKrC2Sc8sB9O//JFvsODTfo=", + "lastModified": 1724082795, + "narHash": "sha256-81Q+CtQO48Ay759VmolvoB4NXrsx8dzfjUnFx6km3H8=", "ref": "refs/heads/master", - "rev": "69320a6cf1445e8fde28537823a26a361f4eb938", - "revCount": 1278, + "rev": "0fc26df29e64a42952291dd4e033e4913ffd8630", + "revCount": 1282, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -63,11 +63,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1721924956, - "narHash": "sha256-Sb1jlyRO+N8jBXEX9Pg9Z1Qb8Bw9QyOgLDNMEpmjZ2M=", + "lastModified": 1723637854, + "narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5ad6a14c6bf098e98800b091668718c336effc95", + "rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9", "type": "github" }, "original": { From fb6609b8a38272cb2aa95c52b6c969d47b4f9983 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 24 Aug 2024 10:44:34 +0800 Subject: [PATCH 307/352] master: migrate deprecated pygit2 commit.hex attr --- artiq/master/experiments.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/artiq/master/experiments.py b/artiq/master/experiments.py index 935872fb0..45bd1b50d 100644 --- a/artiq/master/experiments.py +++ b/artiq/master/experiments.py @@ -206,10 +206,9 @@ class GitBackend: a git hash """ commit, _ = self.git.resolve_refish(rev) - - logger.debug('Resolved git ref "%s" into "%s"', rev, commit.hex) - - return commit.hex + commit_id = str(commit.id) + logger.debug('Resolved git ref "%s" into "%s"', rev, commit_id) + return commit_id def request_rev(self, rev): rev = self._get_pinned_rev(rev) From 9e11e10787661daedeaa73293a30ca2d7a4b01ae Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 24 Aug 2024 10:45:45 +0800 Subject: [PATCH 308/352] test_client: make master termination easier to debug --- artiq/test/test_client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/test/test_client.py b/artiq/test/test_client.py index aa6cae692..ac2b8c741 100644 --- a/artiq/test/test_client.py +++ b/artiq/test/test_client.py @@ -44,7 +44,8 @@ class TestClient(unittest.TestCase): self.device_db_path, *args], encoding="utf8", env=get_env(), text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while self.master.stdout.readline().strip() != "ARTIQ master is now ready.": - pass + if self.master.poll() is not None: + raise IOError("master terminated unexpectedly") def check_and_terminate_master(self): while not ("test content" in self.master.stdout.readline()): From 461db782ba88d542a0b3b60df4ae58d13be75e18 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 27 Aug 2024 23:01:09 +0800 Subject: [PATCH 309/352] flake: update dependencies --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 0e685d397..9065263f8 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1724082795, - "narHash": "sha256-81Q+CtQO48Ay759VmolvoB4NXrsx8dzfjUnFx6km3H8=", + "lastModified": 1724771209, + "narHash": "sha256-B4MTGnqmU59+A0B2APUzFS6vse3dCmhYqVbT/NJtga8=", "ref": "refs/heads/master", - "rev": "0fc26df29e64a42952291dd4e033e4913ffd8630", - "revCount": 1282, + "rev": "600a5c867952eb5f9f7e4574e60f2bb8b29903c2", + "revCount": 1314, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -133,11 +133,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1721561053, - "narHash": "sha256-z3LRhNmKZrjr6rFD0yxtccSa/SWvFIYmb+G/D5d2Jd8=", + "lastModified": 1724304798, + "narHash": "sha256-tQ02N0eXY5W/Z7CrOy3Cu4WjDZDQWb8hYlzsFzr3Mus=", "owner": "m-labs", "repo": "migen", - "rev": "9279e8623f8433bc4f23ac51e5e2331bfe544417", + "rev": "832a7240ba32af9cbd4fdd519ddcb4f912534726", "type": "github" }, "original": { From a7b04505933946cce482981a2cbde3b536458f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Fri, 30 Aug 2024 12:43:38 +0800 Subject: [PATCH 310/352] test/embedding: fix int boundary issues --- artiq/test/coredevice/test_embedding.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 29055bb26..6c7067973 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -650,15 +650,15 @@ class _IntBoundary(EnvExperiment): self.setattr_device("core") self.int32_min = numpy.iinfo(int32).min self.int32_max = numpy.iinfo(int32).max - self.int64_min = numpy.iinfo(int64).min - self.int64_max = numpy.iinfo(int64).max + self.int64_min = int64(numpy.iinfo(int64).min) + self.int64_max = int64(numpy.iinfo(int64).max) @kernel - def test_int32_bounds(self, min_val: int32, max_val: int32): + def test_int32_bounds(self, min_val: int32, max_val: int32) -> bool: return min_val == self.int32_min and max_val == self.int32_max @kernel - def test_int64_bounds(self, min_val: int64, max_val: int64): + def test_int64_bounds(self, min_val: int64, max_val: int64) -> bool: return min_val == self.int64_min and max_val == self.int64_max @kernel From 016691cee3e141a80fab785396c22c7d7fb49664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Fri, 30 Aug 2024 13:21:27 +0800 Subject: [PATCH 311/352] test/performance: port to NAC3 --- artiq/test/coredevice/test_performance.py | 179 +++++++++------------- 1 file changed, 72 insertions(+), 107 deletions(-) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index 2786dc551..f029549a2 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -1,44 +1,45 @@ import os import time import unittest +from typing import Literal + import numpy -from numpy import int32, float64 +from numpy import int32, float64, ndarray from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase +from artiq.coredevice.core import Core + + +bool_list_large = [True] * (1 << 20) +bool_list_small = [True] * (1 << 10) # large: 1MB payload # small: 1KB payload -bytes_large = b"\x00" * (1 << 20) -bytes_small = b"\x00" * (1 << 10) - list_large = [123] * (1 << 18) list_small = [123] * (1 << 8) array_large = numpy.array(list_large, int32) array_small = numpy.array(list_small, int32) -byte_list_large = [True] * (1 << 20) -byte_list_small = [True] * (1 << 10) - received_bytes = 0 time_start = 0 time_end = 0 + +@nac3 class _Transfer(EnvExperiment): + core: KernelInvariant[Core] + count: KernelInvariant[int32] + h2d: Kernel[list[float]] + d2h: Kernel[list[float]] + def build(self): self.setattr_device("core") self.count = 10 self.h2d = [0.0] * self.count self.d2h = [0.0] * self.count - @rpc - def get_bytes(self, large: bool) -> bytes: - if large: - return bytes_large - else: - return bytes_small - @rpc def get_list(self, large: bool) -> list[int32]: if large: @@ -47,14 +48,14 @@ class _Transfer(EnvExperiment): return list_small @rpc - def get_byte_list(self, large: bool) -> list[bool]: + def get_bool_list(self, large: bool) -> list[bool]: if large: - return byte_list_large + return bool_list_large else: - return byte_list_small + return bool_list_small @rpc - def get_array(self, large: bool) -> numpy.ndarray: # NAC3TODO: [int32] + def get_array(self, large: bool) -> ndarray[int32, Literal[1]]: if large: return array_large else: @@ -65,11 +66,19 @@ class _Transfer(EnvExperiment): return string_list @rpc - def sink(self, data): + def sink_bool_list(self, data: list[bool]): pass - @rpc(flags={"async"}) - def sink_async(self, data): + @rpc + def sink_list(self, data: list[int32]): + pass + + @rpc + def sink_array(self, data: ndarray[int32, Literal[1]]): + pass + + @rpc # NAC3TODO (flags={"async"}) + def sink_async(self, data: list[int32]): global received_bytes, time_start, time_end if received_bytes == 0: time_start = time.time() @@ -81,73 +90,48 @@ class _Transfer(EnvExperiment): def get_async_throughput(self) -> float: return 128.0 / (time_end - time_start) + @kernel - def test_bytes(self, large): - def inner(): + def test_bool_list(self, large: bool): + for i in range(self.count): t0 = self.core.get_rtio_counter_mu() - data = self.get_bytes(large) + data = self.get_bool_list(large) t1 = self.core.get_rtio_counter_mu() - self.sink(data) + self.sink_bool_list(data) t2 = self.core.get_rtio_counter_mu() self.h2d[i] = self.core.mu_to_seconds(t1 - t0) self.d2h[i] = self.core.mu_to_seconds(t2 - t1) - for i in range(self.count): - inner() - return (self.h2d, self.d2h) - @kernel - def test_byte_list(self, large): - def inner(): - t0 = self.core.get_rtio_counter_mu() - data = self.get_byte_list(large) - t1 = self.core.get_rtio_counter_mu() - self.sink(data) - t2 = self.core.get_rtio_counter_mu() - self.h2d[i] = self.core.mu_to_seconds(t1 - t0) - self.d2h[i] = self.core.mu_to_seconds(t2 - t1) - + def test_list(self, large: bool): for i in range(self.count): - inner() - return (self.h2d, self.d2h) - - @kernel - def test_list(self, large): - def inner(): t0 = self.core.get_rtio_counter_mu() data = self.get_list(large) t1 = self.core.get_rtio_counter_mu() - self.sink(data) + self.sink_list(data) t2 = self.core.get_rtio_counter_mu() self.h2d[i] = self.core.mu_to_seconds(t1 - t0) self.d2h[i] = self.core.mu_to_seconds(t2 - t1) - for i in range(self.count): - inner() - return (self.h2d, self.d2h) - @kernel - def test_array(self, large): - def inner(): + def test_array(self, large: bool): + for i in range(self.count): t0 = self.core.get_rtio_counter_mu() data = self.get_array(large) t1 = self.core.get_rtio_counter_mu() - self.sink(data) + self.sink_array(data) t2 = self.core.get_rtio_counter_mu() self.h2d[i] = self.core.mu_to_seconds(t1 - t0) self.d2h[i] = self.core.mu_to_seconds(t2 - t1) - for i in range(self.count): - inner() - return (self.h2d, self.d2h) - @kernel - def test_async(self): - data = self.get_bytes(True) + def test_async(self) -> float: + data = self.get_list(True) for _ in range(128): self.sink_async(data) return self.get_async_throughput() + class TransferTest(ExperimentCase): @classmethod def setUpClass(self): @@ -169,59 +153,35 @@ class TransferTest(ExperimentCase): print("| {} | {:>12.2f} | {:>12.2f} |".format( pad(v[0]), v[1], v[2])) - def test_bytes_large(self): + def test_bool_list_large(self): exp = self.create(_Transfer) - results = exp.test_bytes(True) - host_to_device = (1 << 20) / numpy.array(results[0], float64) - device_to_host = (1 << 20) / numpy.array(results[1], float64) + exp.test_bool_list(True) + host_to_device = (1 << 20) / numpy.array(exp.h2d, float64) + device_to_host = (1 << 20) / numpy.array(exp.d2h, float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 - self.results.append(["Bytes (1MB) H2D", host_to_device.mean(), + self.results.append(["Bool List (1MB) H2D", host_to_device.mean(), host_to_device.std()]) - self.results.append(["Bytes (1MB) D2H", device_to_host.mean(), + self.results.append(["Bool List (1MB) D2H", device_to_host.mean(), device_to_host.std()]) - def test_bytes_small(self): + def test_bool_list_small(self): exp = self.create(_Transfer) - results = exp.test_bytes(False) - host_to_device = (1 << 10) / numpy.array(results[0], float64) - device_to_host = (1 << 10) / numpy.array(results[1], float64) + exp.test_bool_list(False) + host_to_device = (1 << 10) / numpy.array(exp.h2d, float64) + device_to_host = (1 << 10) / numpy.array(exp.d2h, float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 - self.results.append(["Bytes (1KB) H2D", host_to_device.mean(), + self.results.append(["Bool List (1KB) H2D", host_to_device.mean(), host_to_device.std()]) - self.results.append(["Bytes (1KB) D2H", device_to_host.mean(), - device_to_host.std()]) - - def test_byte_list_large(self): - exp = self.create(_Transfer) - results = exp.test_byte_list(True) - host_to_device = (1 << 20) / numpy.array(results[0], float64) - device_to_host = (1 << 20) / numpy.array(results[1], float64) - host_to_device /= 1024*1024 - device_to_host /= 1024*1024 - self.results.append(["Bytes List (1MB) H2D", host_to_device.mean(), - host_to_device.std()]) - self.results.append(["Bytes List (1MB) D2H", device_to_host.mean(), - device_to_host.std()]) - - def test_byte_list_small(self): - exp = self.create(_Transfer) - results = exp.test_byte_list(False) - host_to_device = (1 << 10) / numpy.array(results[0], float64) - device_to_host = (1 << 10) / numpy.array(results[1], float64) - host_to_device /= 1024*1024 - device_to_host /= 1024*1024 - self.results.append(["Bytes List (1KB) H2D", host_to_device.mean(), - host_to_device.std()]) - self.results.append(["Bytes List (1KB) D2H", device_to_host.mean(), + self.results.append(["Bool List (1KB) D2H", device_to_host.mean(), device_to_host.std()]) def test_list_large(self): exp = self.create(_Transfer) - results = exp.test_list(True) - host_to_device = (1 << 20) / numpy.array(results[0], float64) - device_to_host = (1 << 20) / numpy.array(results[1], float64) + exp.test_list(True) + host_to_device = (1 << 20) / numpy.array(exp.h2d, float64) + device_to_host = (1 << 20) / numpy.array(exp.d2h, float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["I32 List (1MB) H2D", host_to_device.mean(), @@ -231,9 +191,9 @@ class TransferTest(ExperimentCase): def test_list_small(self): exp = self.create(_Transfer) - results = exp.test_list(False) - host_to_device = (1 << 10) / numpy.array(results[0], float64) - device_to_host = (1 << 10) / numpy.array(results[1], float64) + exp.test_list(False) + host_to_device = (1 << 10) / numpy.array(exp.h2d, float64) + device_to_host = (1 << 10) / numpy.array(exp.d2h, float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["I32 List (1KB) H2D", host_to_device.mean(), @@ -243,9 +203,9 @@ class TransferTest(ExperimentCase): def test_array_large(self): exp = self.create(_Transfer) - results = exp.test_array(True) - host_to_device = (1 << 20) / numpy.array(results[0], float64) - device_to_host = (1 << 20) / numpy.array(results[1], float64) + exp.test_array(True) + host_to_device = (1 << 20) / numpy.array(exp.h2d, float64) + device_to_host = (1 << 20) / numpy.array(exp.d2h, float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["I32 Array (1MB) H2D", host_to_device.mean(), @@ -255,9 +215,9 @@ class TransferTest(ExperimentCase): def test_array_small(self): exp = self.create(_Transfer) - results = exp.test_array(False) - host_to_device = (1 << 10) / numpy.array(results[0], float64) - device_to_host = (1 << 10) / numpy.array(results[1], float64) + exp.test_array(False) + host_to_device = (1 << 10) / numpy.array(exp.h2d, float64) + device_to_host = (1 << 10) / numpy.array(exp.d2h, float64) host_to_device /= 1024*1024 device_to_host /= 1024*1024 self.results.append(["I32 Array (1KB) H2D", host_to_device.mean(), @@ -265,12 +225,17 @@ class TransferTest(ExperimentCase): self.results.append(["I32 Array (1KB) D2H", device_to_host.mean(), device_to_host.std()]) + @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/182") def test_async_throughput(self): exp = self.create(_Transfer) results = exp.test_async() print("Async throughput: {:>6.2f}MiB/s".format(results)) + +@nac3 class _KernelOverhead(EnvExperiment): + core: KernelInvariant[Core] + def build(self): self.setattr_device("core") From aec216897411920727cf4919527323b92ec2c5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Fri, 30 Aug 2024 13:47:48 +0800 Subject: [PATCH 312/352] coredevice: fix seconds_to_mu rounding --- artiq/coredevice/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 92f5f5739..096fbbd16 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -176,7 +176,7 @@ class Core: :param seconds: time (in seconds) to convert. """ - return int64(seconds//self.ref_period) + return round64(seconds/self.ref_period) @portable def mu_to_seconds(self, mu: int64) -> float: From cef423d54719fda0165930fbe6e71f57b1de4e2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Fri, 30 Aug 2024 13:52:24 +0800 Subject: [PATCH 313/352] language/core: make *64 functions return int64 --- artiq/language/core.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/artiq/language/core.py b/artiq/language/core.py index a73d505c6..a3f9faa03 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -8,6 +8,8 @@ from inspect import getfullargspec, getmodule from types import SimpleNamespace from math import floor, ceil +from numpy import int32, int64 + from artiq.language import import_cache @@ -42,13 +44,13 @@ def ConstGeneric(name, constraint): return TypeVar(name, _ConstGenericMarker, constraint) def round64(x): - return round(x) + return int64(round(x)) def floor64(x): - return floor(x) + return int64(floor(x)) def ceil64(x): - return ceil(x) + return int64(ceil(x)) # Delay NAC3 analysis until all referenced variables are supposed to exist on the CPython side. From c763b9b7175e7a9f2a1de313c7034dda63c36f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Fri, 30 Aug 2024 13:57:03 +0800 Subject: [PATCH 314/352] test: skip some broken ones --- artiq/test/coredevice/test_embedding.py | 5 +++++ artiq/test/coredevice/test_rtio.py | 1 + 2 files changed, 6 insertions(+) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 6c7067973..43a42ef3f 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -127,6 +127,7 @@ class _DefaultArg(EnvExperiment): class DefaultArgTest(ExperimentCase): + @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/528") def test_default_arg(self): exp = self.create(_DefaultArg) self.assertEqual(exp.run(), 42) @@ -295,6 +296,7 @@ class _RPCCalls(EnvExperiment): class RPCCallsTest(ExperimentCase): + @unittest.skip("NAC3TODO") def test_args(self): exp = self.create(_RPCCalls) self.assertEqual(exp.args0(), 0) @@ -332,6 +334,7 @@ class _Annotation(EnvExperiment): class AnnotationTest(ExperimentCase): + @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/101") def test_annotation(self): exp = self.create(_Annotation) self.assertEqual(exp.overflow(int64(1)), True) @@ -463,6 +466,7 @@ class _EmptyList(EnvExperiment): class ListTupleTest(ExperimentCase): + @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/529") def test_list_tuple(self): self.create(_ListTuple).run() @@ -535,6 +539,7 @@ class _Assert(EnvExperiment): class AssertTest(ExperimentCase): + @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/530") def test_assert(self): exp = self.create(_Assert) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 1d99c21a2..9c71ba4ce 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -591,6 +591,7 @@ class CoredeviceTest(ExperimentCase): count = self.dataset_mgr.get("count") self.assertEqual(count, 10) + @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/532") def test_pulse_rate(self): """Minimum interval for sustained TTL output switching""" exp = self.execute(PulseRate) From 9f664afb00165788d94679bf7dbb608c161f7f7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Fri, 30 Aug 2024 14:29:40 +0800 Subject: [PATCH 315/352] test/portability: port to NAC3 --- artiq/test/coredevice/test_portability.py | 99 ++++++++++++++++++----- 1 file changed, 77 insertions(+), 22 deletions(-) diff --git a/artiq/test/coredevice/test_portability.py b/artiq/test/coredevice/test_portability.py index 05988fcb2..9ac52ab3f 100644 --- a/artiq/test/coredevice/test_portability.py +++ b/artiq/test/coredevice/test_portability.py @@ -1,6 +1,8 @@ from operator import itemgetter -from fractions import Fraction +from numpy import int32, int64 + +from artiq.coredevice.core import Core from artiq.experiment import * from artiq.sim import devices as sim_devices from artiq.test.hardware_testbench import ExperimentCase @@ -16,13 +18,18 @@ def _run_on_host(k_class, *args, **kwargs): return k_inst +@nac3 class _Primes(EnvExperiment): + core: KernelInvariant[Core] + maximum: KernelInvariant[int32] + def build(self, output_list, maximum): self.setattr_device("core") self.output_list = output_list self.maximum = maximum - def _add_output(self, x): + @rpc + def _add_output(self, x: int32): self.output_list.append(x) @kernel @@ -39,8 +46,11 @@ class _Primes(EnvExperiment): self._add_output(x) +@nac3 class _Math(EnvExperiment): - """Test kernel math""" + core: KernelInvariant[Core] + x: KernelInvariant[float] + x_sqrt: Kernel[float] def build(self): self.setattr_device("core") @@ -52,7 +62,18 @@ class _Math(EnvExperiment): self.x_sqrt = self.x**0.5 +@nac3 class _Misc(EnvExperiment): + core: KernelInvariant[Core] + + input: KernelInvariant[int32] + al: KernelInvariant[list[int32]] + list_copy_in: KernelInvariant[list[float]] + + half_input: Kernel[int32] + acc: Kernel[int32] + list_copy_out: Kernel[list[float]] + def build(self): self.setattr_device("core") @@ -73,7 +94,10 @@ class _Misc(EnvExperiment): self.list_copy_out = self.list_copy_in +@nac3 class _PulseLogger(EnvExperiment): + core: KernelInvariant[Core] + def build(self, parent_test, name): self.setattr_device("core") self.parent_test = parent_test @@ -86,20 +110,29 @@ class _PulseLogger(EnvExperiment): t_usec = round(self.core.mu_to_seconds(t-origin)*1000000) self.parent_test.output_list.append((self.name, t_usec, l, f)) - def on(self, t, f): + @rpc + def on(self, t: int64, f: int32): self._append(t, True, f) - def off(self, t): + @rpc + def off(self, t: int64): self._append(t, False, 0) @kernel - def pulse(self, f, duration): + def pulse(self, f: int32, duration: float): self.on(now_mu(), f) - delay(duration) + self.core.delay(duration) self.off(now_mu()) +@nac3 class _Pulses(EnvExperiment): + core: KernelInvariant[Core] + a: KernelInvariant[_PulseLogger] + b: KernelInvariant[_PulseLogger] + c: KernelInvariant[_PulseLogger] + d: KernelInvariant[_PulseLogger] + def build(self, output_list): self.setattr_device("core") self.output_list = output_list @@ -115,22 +148,28 @@ class _Pulses(EnvExperiment): for i in range(3): with parallel: with sequential: - self.a.pulse(100+i, 20*us) - self.b.pulse(200+i, 20*us) + self.a.pulse(100+i, 20.*us) + self.b.pulse(200+i, 20.*us) with sequential: - self.c.pulse(300+i, 10*us) - self.d.pulse(400+i, 20*us) + self.c.pulse(300+i, 10.*us) + self.d.pulse(400+i, 20.*us) +@nac3 class _MyException(Exception): pass + +@nac3 class _NestedFinally(EnvExperiment): + core: KernelInvariant[Core] + def build(self, trace): self.setattr_device("core") self.trace = trace - def _trace(self, i): + @rpc + def _trace(self, i: int32): self.trace.append(i) @kernel @@ -148,12 +187,17 @@ class _NestedFinally(EnvExperiment): finally: self._trace(2) + +@nac3 class _NestedExceptions(EnvExperiment): + core: KernelInvariant[Core] + def build(self, trace): self.setattr_device("core") self.trace = trace - def _trace(self, i): + @rpc + def _trace(self, i: int32): self.trace.append(i) @kernel @@ -177,12 +221,17 @@ class _NestedExceptions(EnvExperiment): finally: self._trace(4) + +@nac3 class _Exceptions(EnvExperiment): + core: KernelInvariant[Core] + def build(self, trace): self.setattr_device("core") self.trace = trace - def _trace(self, i): + @rpc + def _trace(self, i: int32): self.trace.append(i) @kernel @@ -224,13 +273,19 @@ class _Exceptions(EnvExperiment): self._trace(104) +@nac3 class _RPCExceptions(EnvExperiment): + core: KernelInvariant[Core] + catch: KernelInvariant[bool] + success: Kernel[bool] + def build(self, catch): self.setattr_device("core") self.catch = catch self.success = False + @rpc def exception_raiser(self): raise _MyException @@ -253,13 +308,18 @@ class _RPCExceptions(EnvExperiment): self.success = True +@nac3 class _Keywords(EnvExperiment): + core: KernelInvariant[Core] + value: KernelInvariant[int32] + def build(self, value, output): self.setattr_device("core") - self.value = value + self.value = value self.output = output - def rpc(self, kw): + @rpc + def rpc(self, kw: int32): self.output.append(kw) @kernel @@ -323,6 +383,7 @@ class HostVsDeviceCase(ExperimentCase): uut = self.execute(_RPCExceptions, catch=True) self.assertTrue(uut.success) + @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/533") def test_keywords(self): for f in self.execute, _run_on_host: output = [] @@ -331,9 +392,3 @@ class HostVsDeviceCase(ExperimentCase): output = [] f(_Keywords, value=1, output=output) self.assertEqual(output, [1]) - output = [] - f(_Keywords, value=False, output=output) - self.assertEqual(output, [False]) - output = [] - f(_Keywords, value=True, output=output) - self.assertEqual(output, [True]) From e0aa0615751193376af5a81c345c5e4bca50bfa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Fri, 30 Aug 2024 14:42:37 +0800 Subject: [PATCH 316/352] merge fixes --- artiq/coredevice/core.py | 4 ++-- artiq/test/coredevice/test_portability.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 3e46260dc..146baadce 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -25,8 +25,8 @@ def rtio_get_destination_status(destination: int32) -> bool: def rtio_get_counter() -> int64: raise NotImplementedError("syscall not simulated") -@syscall -def test_exception_id_sync(id: TInt32) -> TNone: +@extern +def test_exception_id_sync(id: int32): raise NotImplementedError("syscall not simulated") artiq_builtins = { diff --git a/artiq/test/coredevice/test_portability.py b/artiq/test/coredevice/test_portability.py index 9ac52ab3f..8c7245559 100644 --- a/artiq/test/coredevice/test_portability.py +++ b/artiq/test/coredevice/test_portability.py @@ -1,3 +1,4 @@ +import unittest from operator import itemgetter from numpy import int32, int64 From 8c6a41eb399a308e8caea8d5a8c50e90ab6029da Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 30 Aug 2024 14:46:38 +0800 Subject: [PATCH 317/352] flake: update dependencies --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 9065263f8..fa9365fe2 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1724771209, - "narHash": "sha256-B4MTGnqmU59+A0B2APUzFS6vse3dCmhYqVbT/NJtga8=", + "lastModified": 1725000338, + "narHash": "sha256-BMAonVm7T9toD1v1pIqKnOx0NT25q4idkk2XVvLyZNI=", "ref": "refs/heads/master", - "rev": "600a5c867952eb5f9f7e4574e60f2bb8b29903c2", - "revCount": 1314, + "rev": "122983f11cf46bed5d6baf42a135997cd597931a", + "revCount": 1324, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -63,11 +63,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1723637854, - "narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=", + "lastModified": 1724819573, + "narHash": "sha256-GnR7/ibgIH1vhoy8cYdmXE6iyZqKqFxQSVkFgosBh6w=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9", + "rev": "71e91c409d1e654808b2621f28a327acfdad8dc2", "type": "github" }, "original": { @@ -117,11 +117,11 @@ ] }, "locked": { - "lastModified": 1717637367, - "narHash": "sha256-4mSm9wl5EMgzzrW6w86IDUevkEOT99FESHGcxcyQbD0=", + "lastModified": 1724921939, + "narHash": "sha256-/S5iip1LHLiCP2VY7PwClDteP9ZMRZvzzKR1LZuV3fs=", "owner": "m-labs", "repo": "sipyco", - "rev": "02b96ec2473a3c3d3c980899de2564ddce949dab", + "rev": "32ddd78ff3641b75054793ea0d5681c951766754", "type": "github" }, "original": { From f913e2740f511d4bb2805933a615984b77143cf6 Mon Sep 17 00:00:00 2001 From: abdul124 Date: Fri, 30 Aug 2024 14:21:55 +0800 Subject: [PATCH 318/352] firmware: sync exception ids and names --- artiq/firmware/ksupport/api.rs | 2 +- artiq/firmware/ksupport/eh_artiq.rs | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 435eaef73..a4744dab3 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -177,7 +177,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ /* * syscall for unit tests * Used in `artiq.tests.coredevice.test_exceptions.ExceptionTest.test_raise_exceptions_kernel` - * This syscall checks that the exception IDs used in the Python `EmbeddingMap` (in `artiq.compiler.embedding`) + * This syscall checks that the exception IDs used in the Python `EmbeddingMap` (in `artiq.language.embedding_map`) * match the `EXCEPTION_ID_LOOKUP` defined in the firmware (`artiq::firmware::ksupport::eh_artiq`) */ api!(test_exception_id_sync = ::eh_artiq::test_exception_id_sync) diff --git a/artiq/firmware/ksupport/eh_artiq.rs b/artiq/firmware/ksupport/eh_artiq.rs index 92806d7b2..68994af0a 100644 --- a/artiq/firmware/ksupport/eh_artiq.rs +++ b/artiq/firmware/ksupport/eh_artiq.rs @@ -328,7 +328,7 @@ extern fn stop_fn(_version: c_int, } } -// Must be kept in sync with `artiq.compiler.embedding` +// Must be kept in sync with `artiq.language.embedding_map` static EXCEPTION_ID_LOOKUP: [(&str, u32); 22] = [ ("RTIOUnderflow", 0), ("RTIOOverflow", 1), @@ -389,3 +389,28 @@ pub extern "C-unwind" fn test_exception_id_sync(exn_id: u32) { unsafe { raise(&exn) }; } +/// Takes as input exception id from host +/// Generates a new exception with: +/// * `id` set to `exn_id` +/// * `message` set to corresponding exception name from `EXCEPTION_ID_LOOKUP` +/// +/// The message is matched on host to ensure correct exception is being referred +/// This test checks the synchronization of exception ids for runtime errors +#[no_mangle] +pub extern "C-unwind" fn test_exception_id_sync(exn_id: u32) { + let message = EXCEPTION_ID_LOOKUP + .iter() + .find_map(|&(name, id)| if id == exn_id { Some(name) } else { None }) + .unwrap_or("unallocated internal exception id"); + + let exn = Exception { + id: exn_id, + file: file!().as_c_slice(), + line: 0, + column: 0, + function: "test_exception_id_sync".as_c_slice(), + message: message.as_c_slice(), + param: [0, 0, 0] + }; + unsafe { raise(&exn) }; +} From bd9648d960b8b61b4152f630a188e50416242ab0 Mon Sep 17 00:00:00 2001 From: abdul124 Date: Fri, 30 Aug 2024 14:22:27 +0800 Subject: [PATCH 319/352] language: sync exception ids and names --- artiq/coredevice/exceptions.py | 23 +++++++++++++++- artiq/language/embedding_map.py | 49 +++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 9a7c2e598..16b0fb533 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -1,6 +1,27 @@ +import builtins +from numpy.linalg import LinAlgError from artiq.language.core import nac3, UnwrapNoneError -from builtins import ZeroDivisionError, ValueError, IndexError, RuntimeError, AssertionError +""" +This file provides class definition for all the exceptions declared in `EmbeddingMap` in `artiq.language.embedding_map` + +For Python builtin exceptions, use the `builtins` module +For ARTIQ specific exceptions, inherit from `Exception` class +""" + +AssertionError = builtins.AssertionError +AttributeError = builtins.AttributeError +IndexError = builtins.IndexError +IOError = builtins.IOError +KeyError = builtins.KeyError +NotImplementedError = builtins.NotImplementedError +OverflowError = builtins.OverflowError +RuntimeError = builtins.RuntimeError +TimeoutError = builtins.TimeoutError +TypeError = builtins.TypeError +ValueError = builtins.ValueError +ZeroDivisionError = builtins.ZeroDivisionError +OSError = builtins.OSError @nac3 class RTIOUnderflow(Exception): diff --git a/artiq/language/embedding_map.py b/artiq/language/embedding_map.py index 14833b730..11739e0b1 100644 --- a/artiq/language/embedding_map.py +++ b/artiq/language/embedding_map.py @@ -7,27 +7,34 @@ class EmbeddingMap: self.function_map = {} self.attributes_writeback = [] - # preallocate exception names - # must be kept in sync with EXCEPTION_ID_LOOKUP in artiq/firmware/ksupport/eh_artiq.rs, - # and src/runtime/src/eh_artiq.rs (Zynq) - self.preallocate_runtime_exception_names(["RuntimeError", - "RTIOUnderflow", - "RTIOOverflow", - "RTIODestinationUnreachable", - "DMAError", - "I2CError", - "CacheError", - "SPIError", - "0:ZeroDivisionError", - "0:IndexError", - "0:ValueError", - "0:RuntimeError", - "0:AssertionError", - "0:KeyError", - "0:NotImplementedError", - "0:OverflowError", - "0:IOError", - "0:UnwrapNoneError"]) + # Keep this list of exceptions in sync with `EXCEPTION_ID_LOOKUP` in `artiq::firmware::ksupport::eh_artiq` + # The exceptions declared here must be defined in `artiq.coredevice.exceptions` + # Verify synchronization by running the test cases in `artiq.test.coredevice.test_exceptions` + self.preallocate_runtime_exception_names([ + "RTIOUnderflow", + "RTIOOverflow", + "RTIODestinationUnreachable", + "DMAError", + "I2CError", + "CacheError", + "SPIError", + "SubkernelError", + + "0:AssertionError", + "0:AttributeError", + "0:IndexError", + "0:IOError", + "0:KeyError", + "0:NotImplementedError", + "0:OverflowError", + "0:RuntimeError", + "0:TimeoutError", + "0:TypeError", + "0:ValueError", + "0:ZeroDivisionError", + "0:LinAlgError", + "UnwrapNoneError", + ]) def preallocate_runtime_exception_names(self, names): for i, name in enumerate(names): From 99f76a7595be08e89d18df40f7e985bc1b68247b Mon Sep 17 00:00:00 2001 From: abdul124 Date: Fri, 30 Aug 2024 14:22:53 +0800 Subject: [PATCH 320/352] test/coredevice: add tests for exception sync --- artiq/test/coredevice/test_exceptions.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/artiq/test/coredevice/test_exceptions.py b/artiq/test/coredevice/test_exceptions.py index 58c297061..7b8fb4d62 100644 --- a/artiq/test/coredevice/test_exceptions.py +++ b/artiq/test/coredevice/test_exceptions.py @@ -3,8 +3,9 @@ import artiq.coredevice.exceptions as exceptions from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase -from artiq.compiler.embedding import EmbeddingMap +from artiq.language.embedding_map import EmbeddingMap from artiq.coredevice.core import test_exception_id_sync +from numpy import int32 """ Test sync in exceptions raised between host and kernel @@ -16,33 +17,34 @@ Considers the following two cases: Ensures same exception is raised on both kernel and host in either case """ -exception_names = EmbeddingMap().str_reverse_map +exception_names = EmbeddingMap().string_map +@nac3 class _TestExceptionSync(EnvExperiment): def build(self): self.setattr_device("core") @rpc - def _raise_exception_host(self, id): + def _raise_exception_host(self, id: int32): exn = exception_names[id].split('.')[-1].split(':')[-1] exn = getattr(exceptions, exn) raise exn @kernel - def raise_exception_host(self, id): + def raise_exception_host(self, id: int32): self._raise_exception_host(id) @kernel - def raise_exception_kernel(self, id): + def raise_exception_kernel(self, id: int32): test_exception_id_sync(id) - + class ExceptionTest(ExperimentCase): def test_raise_exceptions_kernel(self): exp = self.create(_TestExceptionSync) - for id, name in list(exception_names.items())[::-1]: + for id, name in exception_names.items(): name = name.split('.')[-1].split(':')[-1] with self.assertRaises(getattr(exceptions, name)) as ctx: exp.raise_exception_kernel(id) @@ -56,4 +58,3 @@ class ExceptionTest(ExperimentCase): name = name.split('.')[-1].split(':')[-1] with self.assertRaises(getattr(exceptions, name)) as ctx: exp.raise_exception_host(id) - From 2b3cfa9f8df3446f3a112e472c5d98013dcf066a Mon Sep 17 00:00:00 2001 From: abdul124 Date: Fri, 30 Aug 2024 16:54:07 +0800 Subject: [PATCH 321/352] firmware: remove the duplicate test_exception_id_sync --- artiq/firmware/ksupport/eh_artiq.rs | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/artiq/firmware/ksupport/eh_artiq.rs b/artiq/firmware/ksupport/eh_artiq.rs index 68994af0a..190ee735f 100644 --- a/artiq/firmware/ksupport/eh_artiq.rs +++ b/artiq/firmware/ksupport/eh_artiq.rs @@ -388,29 +388,3 @@ pub extern "C-unwind" fn test_exception_id_sync(exn_id: u32) { }; unsafe { raise(&exn) }; } - -/// Takes as input exception id from host -/// Generates a new exception with: -/// * `id` set to `exn_id` -/// * `message` set to corresponding exception name from `EXCEPTION_ID_LOOKUP` -/// -/// The message is matched on host to ensure correct exception is being referred -/// This test checks the synchronization of exception ids for runtime errors -#[no_mangle] -pub extern "C-unwind" fn test_exception_id_sync(exn_id: u32) { - let message = EXCEPTION_ID_LOOKUP - .iter() - .find_map(|&(name, id)| if id == exn_id { Some(name) } else { None }) - .unwrap_or("unallocated internal exception id"); - - let exn = Exception { - id: exn_id, - file: file!().as_c_slice(), - line: 0, - column: 0, - function: "test_exception_id_sync".as_c_slice(), - message: message.as_c_slice(), - param: [0, 0, 0] - }; - unsafe { raise(&exn) }; -} From 770896a64b3229729933835b2af1415734edfca5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 31 Aug 2024 22:01:52 +0800 Subject: [PATCH 322/352] flake: run HITL tests --- flake.nix | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/flake.nix b/flake.nix index a77509c7d..01680ed10 100644 --- a/flake.nix +++ b/flake.nix @@ -407,6 +407,57 @@ touch $out ''; }; + kc705-hitl = pkgs.stdenvNoCC.mkDerivation { + name = "kc705-hitl"; + + __networked = true; # compatibility with old patched Nix + # breaks hydra, https://github.com/NixOS/hydra/issues/1216 + #__impure = true; # Nix 2.8+ + + buildInputs = [ + (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ artiq ps.paramiko ])) + pkgs.llvm_14 + pkgs.openssh + packages.x86_64-linux.openocd-bscanspi # for the bscanspi bitstreams + ]; + phases = [ "buildPhase" ]; + buildPhase = + '' + export HOME=`mktemp -d` + mkdir $HOME/.ssh + cp /opt/hydra_id_ed25519 $HOME/.ssh/id_ed25519 + cp /opt/hydra_id_ed25519.pub $HOME/.ssh/id_ed25519.pub + echo "rpi-1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIACtBFDVBYoAE4fpJCTANZSE0bcVpTR3uvfNvb80C4i5" > $HOME/.ssh/known_hosts + chmod 600 $HOME/.ssh/id_ed25519 + LOCKCTL=$(mktemp -d) + mkfifo $LOCKCTL/lockctl + + cat $LOCKCTL/lockctl | ${pkgs.openssh}/bin/ssh \ + -i $HOME/.ssh/id_ed25519 \ + -o UserKnownHostsFile=$HOME/.ssh/known_hosts \ + rpi-1 \ + 'mkdir -p /tmp/board_lock && flock /tmp/board_lock/kc705-1 -c "echo Ok; cat"' \ + | ( + # End remote flock via FIFO + atexit_unlock() { + echo > $LOCKCTL/lockctl + } + trap atexit_unlock EXIT + + # Read "Ok" line when remote successfully locked + read LOCK_OK + + artiq_flash -t kc705 -H rpi-1 -d ${packages.x86_64-linux.artiq-board-kc705-nist_clock} + sleep 30 + + export ARTIQ_ROOT=`python -c "import artiq; print(artiq.__path__[0])"`/examples/kc705_nist_clock + export ARTIQ_LOW_LATENCY=1 + python -m unittest discover -v artiq.test.coredevice + ) + + touch $out + ''; + }; }; }; From 618e2788d9217960677bd436a0b27253f68d88d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Mon, 2 Sep 2024 12:48:09 +0800 Subject: [PATCH 323/352] test: prevent NAC3 analysis failures of imported but unused methods --- artiq/test/coredevice/test_cache.py | 2 +- artiq/test/coredevice/test_edge_counter.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/test/coredevice/test_cache.py b/artiq/test/coredevice/test_cache.py index 10d586e02..3574711d0 100644 --- a/artiq/test/coredevice/test_cache.py +++ b/artiq/test/coredevice/test_cache.py @@ -9,7 +9,7 @@ from artiq.coredevice.exceptions import CacheError from artiq.test.hardware_testbench import ExperimentCase -@nac3 +# NAC3TODO @nac3 class _Cache(EnvExperiment): core: KernelInvariant[Core] core_cache: KernelInvariant[CoreCache] diff --git a/artiq/test/coredevice/test_edge_counter.py b/artiq/test/coredevice/test_edge_counter.py index 867976d1e..8152a3922 100644 --- a/artiq/test/coredevice/test_edge_counter.py +++ b/artiq/test/coredevice/test_edge_counter.py @@ -19,7 +19,7 @@ class EdgeCounterExp(EnvExperiment): self.setattr_device("loop_out") # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/461 - @kernel + # NAC3TODO @kernel def count_pulse_edges(self, gate_fn) -> tuple[int32, int32]: self.core.break_realtime() with parallel: @@ -27,9 +27,9 @@ class EdgeCounterExp(EnvExperiment): self.core.delay(5. * us) self.loop_out.pulse(10. * us) with sequential: - #gate_fn(10. * us) + gate_fn(10. * us) self.core.delay(1. * us) - #gate_fn(10 * us) + gate_fn(10 * us) return (self.loop_in_counter.fetch_count(), self.loop_in_counter.fetch_count()) From 75d9250463f6702b809c2f62ba18ddea0eaf2ee8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Sep 2024 12:18:17 +0800 Subject: [PATCH 324/352] update dependencies --- flake.lock | 14 +++++++------- windows/PKGBUILD.common | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/flake.lock b/flake.lock index fa9365fe2..519769f85 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1725000338, - "narHash": "sha256-BMAonVm7T9toD1v1pIqKnOx0NT25q4idkk2XVvLyZNI=", + "lastModified": 1725593528, + "narHash": "sha256-pUgwm4mgbXNh5QtkJ9+Fr55dKf3uRSpKeFwlvZz1OkQ=", "ref": "refs/heads/master", - "rev": "122983f11cf46bed5d6baf42a135997cd597931a", - "revCount": 1324, + "rev": "6098b1b853d759de6a2980220faa217c25a2fb2b", + "revCount": 1329, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -63,11 +63,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1724819573, - "narHash": "sha256-GnR7/ibgIH1vhoy8cYdmXE6iyZqKqFxQSVkFgosBh6w=", + "lastModified": 1725432240, + "narHash": "sha256-+yj+xgsfZaErbfYM3T+QvEE2hU7UuE+Jf0fJCJ8uPS0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "71e91c409d1e654808b2621f28a327acfdad8dc2", + "rev": "ad416d066ca1222956472ab7d0555a6946746a80", "type": "github" }, "original": { diff --git a/windows/PKGBUILD.common b/windows/PKGBUILD.common index e8c58f2c7..4463788eb 100644 --- a/windows/PKGBUILD.common +++ b/windows/PKGBUILD.common @@ -7,7 +7,7 @@ sha256sums=("SKIP") build() { mkdir clang64 - export PYTHONPATH=`pwd`/clang64/lib/python3.11/site-packages + export PYTHONPATH=`pwd`/clang64/lib/python3.12/site-packages chmod +w -R source cd source wine-msys2-build python setup.py install --single-version-externally-managed --prefix=../clang64 --record=setuptools-sucks.txt From 098e2399b85357499b2e86b80ee6fdb0fc6332ad Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 30 Sep 2024 14:28:51 +0800 Subject: [PATCH 325/352] flake: update dependencies --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 519769f85..aad9dcd89 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1725593528, - "narHash": "sha256-pUgwm4mgbXNh5QtkJ9+Fr55dKf3uRSpKeFwlvZz1OkQ=", + "lastModified": 1727677650, + "narHash": "sha256-h8T+VbC0lohGz7YdO0c/Sn0UceVb3ghqd0IuxJR6Amo=", "ref": "refs/heads/master", - "rev": "6098b1b853d759de6a2980220faa217c25a2fb2b", - "revCount": 1329, + "rev": "6c8382219fb98a4bc9a65d8fa2204fce8d704e89", + "revCount": 1342, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -63,11 +63,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1725432240, - "narHash": "sha256-+yj+xgsfZaErbfYM3T+QvEE2hU7UuE+Jf0fJCJ8uPS0=", + "lastModified": 1727348695, + "narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ad416d066ca1222956472ab7d0555a6946746a80", + "rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784", "type": "github" }, "original": { @@ -133,11 +133,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1724304798, - "narHash": "sha256-tQ02N0eXY5W/Z7CrOy3Cu4WjDZDQWb8hYlzsFzr3Mus=", + "lastModified": 1727677091, + "narHash": "sha256-Zg3SQnTwMM/VkOGKogbPyuCC2NhLy8HB2SPEUWWNgCU=", "owner": "m-labs", "repo": "migen", - "rev": "832a7240ba32af9cbd4fdd519ddcb4f912534726", + "rev": "c19ae9f8ae162ffe2d310a92bfce53ac2a821bc8", "type": "github" }, "original": { From 5dcdeb6e0d85ecd44f47f026519f3b1134249407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Mon, 30 Sep 2024 14:58:02 +0800 Subject: [PATCH 326/352] flake: update qasync, sync with nixpkgs --- flake.nix | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/flake.nix b/flake.nix index 01680ed10..3d5b7843c 100644 --- a/flake.nix +++ b/flake.nix @@ -60,15 +60,21 @@ qasync = pkgs.python3Packages.buildPythonPackage rec { pname = "qasync"; - version = "0.25.0"; + version = "0.27.1"; + format = "pyproject"; src = pkgs.fetchFromGitHub { owner = "CabbageDevelopment"; repo = "qasync"; - rev = "v${version}"; - sha256 = "sha256-lfH8FNA8cP7dmxR+ihoe2Gr8uOxXHdqn1AhNLIkX5ko="; + rev = "refs/tags/v${version}"; + sha256 = "sha256-oXzwilhJ1PhodQpOZjnV9gFuoDy/zXWva9LhhK3T00g="; }; + postPatch = '' + rm qasync/_windows.py # Ignoring it is not taking effect and it will not be used on Linux + ''; + buildInputs = [ pkgs.python3Packages.poetry-core ]; propagatedBuildInputs = [ pkgs.python3Packages.pyqt6 ]; - nativeCheckInputs = [ pkgs.python3Packages.pytest-runner pkgs.python3Packages.pytestCheckHook ]; + checkInputs = [ pkgs.python3Packages.pytestCheckHook ]; + pythonImportsCheck = [ "qasync" ]; disabledTestPaths = [ "tests/test_qeventloop.py" ]; }; From 347344053431a0dfa7ac5cd672b8aee68f5b1f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Mon, 30 Sep 2024 17:47:05 +0800 Subject: [PATCH 327/352] test: enable async RPC tests --- artiq/test/coredevice/test_embedding.py | 2 +- artiq/test/coredevice/test_performance.py | 13 +++++-------- artiq/test/coredevice/test_stress.py | 3 +-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 43a42ef3f..1483277c4 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -348,7 +348,7 @@ class _Async(EnvExperiment): def build(self): self.setattr_device("core") - @rpc # NAC3TODO (flags={"async"}) + @rpc(flags={"async"}) def recv_async(self, data: list[int32]): pass diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index f029549a2..2f3bc17e4 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -77,20 +77,18 @@ class _Transfer(EnvExperiment): def sink_array(self, data: ndarray[int32, Literal[1]]): pass - @rpc # NAC3TODO (flags={"async"}) + @rpc(flags={"async"}) def sink_async(self, data: list[int32]): global received_bytes, time_start, time_end if received_bytes == 0: time_start = time.time() - received_bytes += len(data) + received_bytes += 4*len(data) if received_bytes == (1024 ** 2)*128: time_end = time.time() - @rpc def get_async_throughput(self) -> float: return 128.0 / (time_end - time_start) - @kernel def test_bool_list(self, large: bool): for i in range(self.count): @@ -125,11 +123,10 @@ class _Transfer(EnvExperiment): self.d2h[i] = self.core.mu_to_seconds(t2 - t1) @kernel - def test_async(self) -> float: + def test_async(self): data = self.get_list(True) for _ in range(128): self.sink_async(data) - return self.get_async_throughput() class TransferTest(ExperimentCase): @@ -225,10 +222,10 @@ class TransferTest(ExperimentCase): self.results.append(["I32 Array (1KB) D2H", device_to_host.mean(), device_to_host.std()]) - @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/182") def test_async_throughput(self): exp = self.create(_Transfer) - results = exp.test_async() + exp.test_async() + results = exp.get_async_throughput() print("Async throughput: {:>6.2f}MiB/s".format(results)) diff --git a/artiq/test/coredevice/test_stress.py b/artiq/test/coredevice/test_stress.py index 4f2183a41..4e3f6d36c 100644 --- a/artiq/test/coredevice/test_stress.py +++ b/artiq/test/coredevice/test_stress.py @@ -13,8 +13,7 @@ class _Stress(EnvExperiment): def build(self): self.setattr_device("core") - # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/182 - @rpc #(flags={"async"}) + @rpc(flags={"async"}) def sink(self, data: int32): pass From 28a229a10c9f0df91abf8c38236a70b99a068709 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Nov 2024 12:51:27 +0800 Subject: [PATCH 328/352] update dependencies --- flake.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/flake.lock b/flake.lock index aad9dcd89..61c262d09 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1727677650, - "narHash": "sha256-h8T+VbC0lohGz7YdO0c/Sn0UceVb3ghqd0IuxJR6Amo=", + "lastModified": 1731732011, + "narHash": "sha256-+TMO4LyDUR/NA7BQduPavWPfEXnKjl2qm4VP1oPFv6E=", "ref": "refs/heads/master", - "rev": "6c8382219fb98a4bc9a65d8fa2204fce8d704e89", - "revCount": 1342, + "rev": "230982dc844fb6be1b91318c41dcbdf12eb9466d", + "revCount": 1376, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -63,11 +63,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1727348695, - "narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=", + "lastModified": 1731319897, + "narHash": "sha256-PbABj4tnbWFMfBp6OcUK5iGy1QY+/Z96ZcLpooIbuEI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784", + "rev": "dc460ec76cbff0e66e269457d7b728432263166c", "type": "github" }, "original": { @@ -117,11 +117,11 @@ ] }, "locked": { - "lastModified": 1724921939, - "narHash": "sha256-/S5iip1LHLiCP2VY7PwClDteP9ZMRZvzzKR1LZuV3fs=", + "lastModified": 1728371104, + "narHash": "sha256-PPnAyDedUQ7Og/Cby9x5OT9wMkNGTP8GS53V6N/dk4w=", "owner": "m-labs", "repo": "sipyco", - "rev": "32ddd78ff3641b75054793ea0d5681c951766754", + "rev": "094a6cd63ffa980ef63698920170e50dc9ba77fd", "type": "github" }, "original": { @@ -149,11 +149,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1715647536, - "narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=", + "lastModified": 1729234629, + "narHash": "sha256-TLsTCXV5AC2xh+bS7EhBVBKqdqIU3eKrnlWcFF9LtAM=", "ref": "refs/heads/master", - "rev": "fea9de558c730bc394a5936094ae95bb9d6fa726", - "revCount": 2455, + "rev": "6085a312bca26adeca6584e37d08c8ba2e1d6e38", + "revCount": 2460, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From 5f9ddf1ef41d73603d531f0600dafc9f61ba940f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Nov 2024 13:44:54 +0800 Subject: [PATCH 329/352] flake: update dependencies --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 61c262d09..07c09fe88 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1731732011, - "narHash": "sha256-+TMO4LyDUR/NA7BQduPavWPfEXnKjl2qm4VP1oPFv6E=", + "lastModified": 1731735709, + "narHash": "sha256-7L5CB5skLRJ02KGPy4c1elEc83rhvYFsxgNGEBf5QXY=", "ref": "refs/heads/master", - "rev": "230982dc844fb6be1b91318c41dcbdf12eb9466d", - "revCount": 1376, + "rev": "2cee7604046e5433f4bfcabd5b964faca1cc5949", + "revCount": 1377, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From b84017e7eaf7ec1203d318365d9e729953cf656a Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 18 Nov 2024 15:15:01 +0800 Subject: [PATCH 330/352] kernel core: pass return value --- artiq/coredevice/comm_kernel.py | 7 ++++++- artiq/coredevice/core.py | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index e829b2fc3..a847115ab 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -689,7 +689,12 @@ class CommKernel: if service_id == 0: def service(*values): - counter = 0 + if embedding_map.expects_return: + embedding_map.return_value = values[0] + counter = 1 + else: + counter = 0 + for obj in embedding_map.attributes_writeback: old_val = obj["obj"] if "fields" in obj: diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 146baadce..a7ea27269 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -123,6 +123,10 @@ class Core: self._run_compiled(kernel_library, embedding_map) + # set by NAC3 + if embedding_map.expects_return: + return embedding_map.return_value + def _run_compiled(self, kernel_library, embedding_map): if self.first_run: self.comm.check_system_info() From 34d0ba956322c018f6737d12a1844fd19dec57f0 Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 18 Nov 2024 15:15:43 +0800 Subject: [PATCH 331/352] coredevice: re-enable annotation test --- artiq/test/coredevice/test_embedding.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 1483277c4..ec414e2f6 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -323,7 +323,6 @@ class _Annotation(EnvExperiment): def build(self): self.setattr_device("core") - # NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/101 @kernel def overflow(self, x: int64) -> bool: return (x << 32) != int64(0) @@ -334,7 +333,6 @@ class _Annotation(EnvExperiment): class AnnotationTest(ExperimentCase): - @unittest.skip("NAC3TODO https://git.m-labs.hk/M-Labs/nac3/issues/101") def test_annotation(self): exp = self.create(_Annotation) self.assertEqual(exp.overflow(int64(1)), True) From 28c9de3e251daa89a8c9fd79d5ab64a3ec03bac6 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Tue, 19 Nov 2024 17:21:28 +0800 Subject: [PATCH 332/352] inject fake module for experiments submitted by content --- artiq/coredevice/core.py | 6 +++++- artiq/language/core.py | 6 ++++++ artiq/master/worker_impl.py | 5 ++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index a7ea27269..dcd9c9ef8 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -102,7 +102,11 @@ class Core: raise NotImplementedError if not self.analyzed: - self.compiler.analyze(core_language._registered_functions, core_language._registered_classes) + self.compiler.analyze( + core_language._registered_functions, + core_language._registered_classes, + core_language._registered_modules + ) self.analyzed = True if hasattr(method, "__self__"): diff --git a/artiq/language/core.py b/artiq/language/core.py index a3f9faa03..7e970e420 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -56,6 +56,7 @@ def ceil64(x): # Delay NAC3 analysis until all referenced variables are supposed to exist on the CPython side. _registered_functions = set() _registered_classes = set() +_registered_modules = set() def _register_function(fun): import_cache.add_module_to_cache(getmodule(fun)) @@ -65,6 +66,11 @@ def _register_class(cls): import_cache.add_module_to_cache(getmodule(cls)) _registered_classes.add(cls) +def register_content_module(module): + # for kernels sent by content, they have no modules + # thus their source must be analyzed instead + _registered_modules.add(module) + def extern(function): """Decorates a function declaration defined by the core device runtime.""" diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 86f08b060..916c43728 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -30,7 +30,9 @@ from artiq.master.worker_db import DeviceManager, DatasetManager, DummyDevice from artiq.language.environment import ( is_public_experiment, TraceArgumentManager, ProcessArgumentManager ) -from artiq.language.core import set_watchdog_factory, TerminationRequested +from artiq.language.core import ( + register_content_module, set_watchdog_factory, TerminationRequested +) from artiq.language import import_cache from artiq import __version__ as artiq_version @@ -166,6 +168,7 @@ def get_experiment_from_content(content, class_name): StringLoader(fake_filename, content) ) module = importlib.util.module_from_spec(spec) + register_content_module(module) spec.loader.exec_module(module) linecache.lazycache(fake_filename, module.__dict__) return tools.get_experiment(module, class_name) From 2d1a33ea139e2ae2b76ca2f5f2f79e4beddb9b6b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Nov 2024 19:45:32 +0800 Subject: [PATCH 333/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 07c09fe88..9ac2afd42 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1731735709, - "narHash": "sha256-7L5CB5skLRJ02KGPy4c1elEc83rhvYFsxgNGEBf5QXY=", + "lastModified": 1732275783, + "narHash": "sha256-4hcl9CwxNfl3JGDog3eEHXxMi6VVHqAP/L9JB4Kyq7w=", "ref": "refs/heads/master", - "rev": "2cee7604046e5433f4bfcabd5b964faca1cc5949", - "revCount": 1377, + "rev": "f6745b987fc4ae62c791913b7ed79cc0637b94e2", + "revCount": 1396, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 3983933153f4723d15eba2a042fb5b5ac54497a0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Nov 2024 20:32:25 +0800 Subject: [PATCH 334/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 9ac2afd42..918c7dfc7 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1732275783, - "narHash": "sha256-4hcl9CwxNfl3JGDog3eEHXxMi6VVHqAP/L9JB4Kyq7w=", + "lastModified": 1732278630, + "narHash": "sha256-8SiaKz8WnbSv2Vhe9cVPwHgEuCAxYnByNthxnRr3WSU=", "ref": "refs/heads/master", - "rev": "f6745b987fc4ae62c791913b7ed79cc0637b94e2", - "revCount": 1396, + "rev": "5651e00688243a10cf7498c789239c9ebd71adab", + "revCount": 1397, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 45115d0a4839b6f65b8b3d71ac6e87a94ee2dc41 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Nov 2024 19:13:06 +0800 Subject: [PATCH 335/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 918c7dfc7..f625e4b05 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1732278630, - "narHash": "sha256-8SiaKz8WnbSv2Vhe9cVPwHgEuCAxYnByNthxnRr3WSU=", + "lastModified": 1732791173, + "narHash": "sha256-t9dxuzEea5CTFEDJOJfOrt7C3NyPOB7UpbOEDgFTU0w=", "ref": "refs/heads/master", - "rev": "5651e00688243a10cf7498c789239c9ebd71adab", - "revCount": 1397, + "rev": "015714eee17acc3d34bd0a6b2048275d1b5542cc", + "revCount": 1405, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 07170ff7c4ed7ab4fdb548b44c2d27c741e026eb Mon Sep 17 00:00:00 2001 From: occheung Date: Tue, 3 Dec 2024 16:46:15 +0800 Subject: [PATCH 336/352] exceptions: relocate preallocations to NAC3 --- artiq/firmware/ksupport/eh_artiq.rs | 2 +- artiq/language/embedding_map.py | 36 ----------------------------- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/artiq/firmware/ksupport/eh_artiq.rs b/artiq/firmware/ksupport/eh_artiq.rs index 190ee735f..84aff00ca 100644 --- a/artiq/firmware/ksupport/eh_artiq.rs +++ b/artiq/firmware/ksupport/eh_artiq.rs @@ -328,7 +328,7 @@ extern fn stop_fn(_version: c_int, } } -// Must be kept in sync with `artiq.language.embedding_map` +// Must be kept in sync with `nac3artiq::Nac3::new` static EXCEPTION_ID_LOOKUP: [(&str, u32); 22] = [ ("RTIOUnderflow", 0), ("RTIOOverflow", 1), diff --git a/artiq/language/embedding_map.py b/artiq/language/embedding_map.py index 11739e0b1..13da0a8ca 100644 --- a/artiq/language/embedding_map.py +++ b/artiq/language/embedding_map.py @@ -7,42 +7,6 @@ class EmbeddingMap: self.function_map = {} self.attributes_writeback = [] - # Keep this list of exceptions in sync with `EXCEPTION_ID_LOOKUP` in `artiq::firmware::ksupport::eh_artiq` - # The exceptions declared here must be defined in `artiq.coredevice.exceptions` - # Verify synchronization by running the test cases in `artiq.test.coredevice.test_exceptions` - self.preallocate_runtime_exception_names([ - "RTIOUnderflow", - "RTIOOverflow", - "RTIODestinationUnreachable", - "DMAError", - "I2CError", - "CacheError", - "SPIError", - "SubkernelError", - - "0:AssertionError", - "0:AttributeError", - "0:IndexError", - "0:IOError", - "0:KeyError", - "0:NotImplementedError", - "0:OverflowError", - "0:RuntimeError", - "0:TimeoutError", - "0:TypeError", - "0:ValueError", - "0:ZeroDivisionError", - "0:LinAlgError", - "UnwrapNoneError", - ]) - - def preallocate_runtime_exception_names(self, names): - for i, name in enumerate(names): - if ":" not in name: - name = "0:artiq.coredevice.exceptions." + name - exn_id = self.store_str(name) - assert exn_id == i - def store_function(self, key, fun): self.function_map[key] = fun return key From 4659b51bd828d0f23e385d955f155dfae96e0c95 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 4 Dec 2024 21:30:55 +0800 Subject: [PATCH 337/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index f625e4b05..2146db18d 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1732791173, - "narHash": "sha256-t9dxuzEea5CTFEDJOJfOrt7C3NyPOB7UpbOEDgFTU0w=", + "lastModified": 1733215546, + "narHash": "sha256-kOz/+z/m7l6ykNnvvaXftfYnLv7iFYECCjE7TmF/oi8=", "ref": "refs/heads/master", - "rev": "015714eee17acc3d34bd0a6b2048275d1b5542cc", - "revCount": 1405, + "rev": "964945d244f09a37f55d476f9675a616442a425a", + "revCount": 1408, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 3b2bc4b6bbe20f1150ad4b12eed208a9b174da35 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 13 Dec 2024 20:04:16 +0800 Subject: [PATCH 338/352] flake: update nac3 --- flake.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 2146db18d..5a71657ca 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1733215546, - "narHash": "sha256-kOz/+z/m7l6ykNnvvaXftfYnLv7iFYECCjE7TmF/oi8=", + "lastModified": 1734090121, + "narHash": "sha256-pZkQJLvvhQUjDdBFlLzvu4Du1KJJmwyC4ndGMU1EZZc=", "ref": "refs/heads/master", - "rev": "964945d244f09a37f55d476f9675a616442a425a", - "revCount": 1408, + "rev": "1531b6cc98f59e0e2cba4dac81b5a279101245f5", + "revCount": 1441, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -63,11 +63,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1731319897, - "narHash": "sha256-PbABj4tnbWFMfBp6OcUK5iGy1QY+/Z96ZcLpooIbuEI=", + "lastModified": 1733940404, + "narHash": "sha256-Pj39hSoUA86ZePPF/UXiYHHM7hMIkios8TYG29kQT4g=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "dc460ec76cbff0e66e269457d7b728432263166c", + "rev": "5d67ea6b4b63378b9c13be21e2ec9d1afc921713", "type": "github" }, "original": { @@ -117,11 +117,11 @@ ] }, "locked": { - "lastModified": 1728371104, - "narHash": "sha256-PPnAyDedUQ7Og/Cby9x5OT9wMkNGTP8GS53V6N/dk4w=", + "lastModified": 1733921114, + "narHash": "sha256-nx+Ot4EYQHLldVq3QQxHhQ+gI/BnBk/aLDHD8eDG2qE=", "owner": "m-labs", "repo": "sipyco", - "rev": "094a6cd63ffa980ef63698920170e50dc9ba77fd", + "rev": "aff9cbbf783b9d703affc5f818ebbc95615c2ea0", "type": "github" }, "original": { From 977f2f3661817404a24464825a4ac3f655dd2577 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 15 Dec 2024 21:48:12 +0800 Subject: [PATCH 339/352] test_rtio: add missing annotations --- artiq/test/coredevice/test_rtio.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 9c71ba4ce..1c46f90e1 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -676,11 +676,17 @@ class CoredeviceTest(ExperimentCase): self.assertEqual(dt, 8000) +@nac3 class RPCTiming(EnvExperiment): + core: KernelInvariant[Core] + repeats: KernelInvariant[int32] + ts: Kernel[list[float]] + def build(self, repeats=100): self.setattr_device("core") self.repeats = repeats + @rpc def nop(self): pass From 62faca81e9fae576f9e4d733b4d5ab48199f82a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Tue, 17 Dec 2024 17:17:10 +0800 Subject: [PATCH 340/352] flake: remove pythonparser --- flake.nix | 5 ----- 1 file changed, 5 deletions(-) diff --git a/flake.nix b/flake.nix index ae69cb6f5..e07a4ec14 100644 --- a/flake.nix +++ b/flake.nix @@ -34,11 +34,6 @@ submodules = true; flake = false; }; - - src-pythonparser = { - url = "github:m-labs/pythonparser"; - flake = false; - }; }; outputs = { self, rust-overlay, sipyco, nac3, artiq-comtools, src-migen, src-misoc }: From 7c93a69e6f91e59c024c64c7894cdc72b0c3e6ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Tue, 17 Dec 2024 17:29:11 +0800 Subject: [PATCH 341/352] ad9834: port to nac3 --- artiq/coredevice/ad9834.py | 65 +++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/artiq/coredevice/ad9834.py b/artiq/coredevice/ad9834.py index 306aa712d..1a6dd9b90 100644 --- a/artiq/coredevice/ad9834.py +++ b/artiq/coredevice/ad9834.py @@ -5,10 +5,12 @@ RTIO Driver for the Analog Devices AD9834 DDS via 3-wire SPI interface. # https://www.analog.com/media/en/technical-documentation/data-sheets/AD9834.pdf # https://www.analog.com/media/en/technical-documentation/app-notes/an-1070.pdf -from artiq.coredevice import spi2 as spi +from numpy import int32 + +from artiq.coredevice.core import Core +from artiq.coredevice.spi2 import * from artiq.experiment import * from artiq.language.core import * -from artiq.language.types import * from artiq.language.units import * AD9834_B28 = 1 << 13 @@ -34,6 +36,7 @@ AD9834_PHASE_REG_1 = AD9834_PHASE_REG | (1 << 13) PHASE_REGS = [AD9834_PHASE_REG_0, AD9834_PHASE_REG_1] +@nac3 class AD9834: """ AD9834 DDS driver. @@ -51,14 +54,18 @@ class AD9834: :param core_device: Core device name (default: "core"). """ - kernel_invariants = {"core", "bus", "spi_freq", "clk_freq"} + core: KernelInvariant[Core] + bus: KernelInvariant[SPIMaster] + spi_freq: KernelInvariant[float] + clk_freq: KernelInvariant[float] + ctrl_reg: Kernel[int32] def __init__( - self, dmgr, spi_device, spi_freq=10 * MHz, clk_freq=75 * MHz, core_device="core" + self, dmgr, spi_device, spi_freq=10. * MHz, clk_freq=75. * MHz, core_device="core" ): self.core = dmgr.get(core_device) self.bus = dmgr.get(spi_device) - assert spi_freq <= 40 * MHz, "SPI frequency exceeds maximum value of 40 MHz" + assert spi_freq <= 40. * MHz, "SPI frequency exceeds maximum value of 40 MHz" self.spi_freq = spi_freq self.clk_freq = clk_freq self.ctrl_reg = 0x0000 # Reset control register @@ -81,11 +88,11 @@ class AD9834: This method should be called before any other operations are performed on the AD9834 to ensure that the device is in a known state. """ - self.bus.set_config(spi.SPI_CLK_POLARITY | spi.SPI_END, 16, self.spi_freq, 1) + self.bus.set_config(SPI_CLK_POLARITY | SPI_END, 16, self.spi_freq, 1) self.enable_reset() @kernel - def set_frequency_reg(self, freq_reg, frequency: TFloat): + def set_frequency_reg(self, freq_reg: int32, frequency: float): """ Set the frequency for the specified frequency register. @@ -107,10 +114,11 @@ class AD9834: then sends the fourteen least significant bits LSBs and fourteen most significant bits MSBs in two consecutive writes to the specified frequency register. """ - if freq_reg not in FREQ_REGS: - raise ValueError("Invalid frequency register") + # NAC3TODO + #if freq_reg not in FREQ_REGS: + # raise ValueError("Invalid frequency register") assert frequency <= 37.5 * MHz, "Frequency exceeds maximum value of 37.5 MHz" - freq_word = int((frequency * (1 << 28)) / self.clk_freq) & 0x0FFFFFFF + freq_word = int32((frequency * float(1 << 28)) / self.clk_freq) & 0x0FFFFFFF self.ctrl_reg |= AD9834_B28 self.write(self.ctrl_reg) lsb = freq_word & 0x3FFF @@ -119,7 +127,7 @@ class AD9834: self.write(freq_reg | msb) @kernel - def set_frequency_reg_msb(self, freq_reg, word: TInt32): + def set_frequency_reg_msb(self, freq_reg: int32, word: int32): """ Set the fourteen most significant bits MSBs of the specified frequency register. @@ -134,15 +142,16 @@ class AD9834: indicate that the MSB is being sent, and then writes the updated control register followed by the MSB value to the specified frequency register. """ - if freq_reg not in FREQ_REGS: - raise ValueError("Invalid frequency register") + # NAC3TODO + #if freq_reg not in FREQ_REGS: + # raise ValueError("Invalid frequency register") self.ctrl_reg &= ~AD9834_B28 self.ctrl_reg |= AD9834_HLB self.write(self.ctrl_reg) self.write(freq_reg | (word & 0x3FFF)) @kernel - def set_frequency_reg_lsb(self, freq_reg, word: TInt32): + def set_frequency_reg_lsb(self, freq_reg: int32, word: int32): """ Set the fourteen least significant bits LSBs of the specified frequency register. @@ -156,15 +165,16 @@ class AD9834: The method first clears the appropriate control bits and writes the updated control register followed by the LSB value to the specified frequency register. """ - if freq_reg not in FREQ_REGS: - raise ValueError("Invalid frequency register") + # NAC3TODO + #if freq_reg not in FREQ_REGS: + # raise ValueError("Invalid frequency register") self.ctrl_reg &= ~AD9834_B28 self.ctrl_reg &= ~AD9834_HLB self.write(self.ctrl_reg) self.write(freq_reg | (word & 0x3FFF)) @kernel - def select_frequency_reg(self, freq_reg): + def select_frequency_reg(self, freq_reg: int32): """ Select the active frequency register for the phase accumulator. @@ -175,8 +185,9 @@ class AD9834: :param freq_reg: The frequency register to select. Must be one of :const:`AD9834_FREQ_REG_0` or :const:`AD9834_FREQ_REG_1`. """ - if freq_reg not in FREQ_REGS: - raise ValueError("Invalid frequency register") + # NAC3TODO + #if freq_reg not in FREQ_REGS: + # raise ValueError("Invalid frequency register") if freq_reg == FREQ_REGS[0]: self.ctrl_reg &= ~AD9834_FSEL else: @@ -186,7 +197,7 @@ class AD9834: self.write(self.ctrl_reg) @kernel - def set_phase_reg(self, phase_reg, phase: TInt32): + def set_phase_reg(self, phase_reg: int32, phase: int32): """ Set the phase for the specified phase register. @@ -199,13 +210,14 @@ class AD9834: The method masks the phase value to ensure it fits within the 12-bit limit and writes it to the specified phase register. """ - if phase_reg not in PHASE_REGS: - raise ValueError("Invalid phase register") + # NAC3TODO + #if phase_reg not in PHASE_REGS: + # raise ValueError("Invalid phase register") phase_word = phase & 0x0FFF self.write(phase_reg | phase_word) @kernel - def select_phase_reg(self, phase_reg): + def select_phase_reg(self, phase_reg: int32): """ Select the active phase register for the phase accumulator. @@ -216,8 +228,9 @@ class AD9834: :param phase_reg: The phase register to select. Must be one of :const:`AD9834_PHASE_REG_0` or :const:`AD9834_PHASE_REG_1`. """ - if phase_reg not in PHASE_REGS: - raise ValueError("Invalid phase register") + # NAC3TODO + #if phase_reg not in PHASE_REGS: + # raise ValueError("Invalid phase register") if phase_reg == PHASE_REGS[0]: self.ctrl_reg &= ~AD9834_PSEL else: @@ -380,7 +393,7 @@ class AD9834: self.write(self.ctrl_reg) @kernel - def write(self, data: TInt32): + def write(self, data: int32): """ Write a 16-bit word to the AD9834. From a57cf3e1cae7a62b408f26ea55630dac0a18249b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 20 Dec 2024 13:08:43 +0800 Subject: [PATCH 342/352] remove lit tests --- .../test/lit/exceptions/finally_catch_try.py | 19 ------------------ artiq/test/lit/exceptions/finally_try.py | 20 ------------------- 2 files changed, 39 deletions(-) delete mode 100644 artiq/test/lit/exceptions/finally_catch_try.py delete mode 100644 artiq/test/lit/exceptions/finally_try.py diff --git a/artiq/test/lit/exceptions/finally_catch_try.py b/artiq/test/lit/exceptions/finally_catch_try.py deleted file mode 100644 index c1b500a78..000000000 --- a/artiq/test/lit/exceptions/finally_catch_try.py +++ /dev/null @@ -1,19 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def doit(): - try: - try: - raise RuntimeError("Error") - except ValueError: - print("ValueError") - except RuntimeError: - print("Caught") - finally: - print("Cleanup") - -doit() - -# CHECK-L: Caught -# CHECK-NEXT-L: Cleanup diff --git a/artiq/test/lit/exceptions/finally_try.py b/artiq/test/lit/exceptions/finally_try.py deleted file mode 100644 index 377ca1c06..000000000 --- a/artiq/test/lit/exceptions/finally_try.py +++ /dev/null @@ -1,20 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: exceptions - -def doit(): - try: - try: - raise RuntimeError("Error") - except ValueError: - print("ValueError") - finally: - print("Cleanup") - -try: - doit() -except RuntimeError: - print("Caught") - -# CHECK-L: Cleanup -# CHECK-NEXT-L: Caught From b280ac535337ee5058008c7de24f4f7cfd8c9108 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 30 Dec 2024 19:33:58 +0800 Subject: [PATCH 343/352] flake: update dependencies --- flake.lock | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/flake.lock b/flake.lock index 5a71657ca..8eb7c3fdf 100644 --- a/flake.lock +++ b/flake.lock @@ -12,11 +12,11 @@ ] }, "locked": { - "lastModified": 1720768567, - "narHash": "sha256-3VoK7o5MtHtbHLrc6Pv+eQWFtaz5Gd/YWyV5TD3c5Ss=", + "lastModified": 1734270714, + "narHash": "sha256-7bzGn/hXLIsLQHGQsvo+uoIFUrw9DjXSlMC449BY4ME=", "owner": "m-labs", "repo": "artiq-comtools", - "rev": "f93570d8f2ed5a3cfb3e1c16ab00f2540551e994", + "rev": "7e3152314af8f5987370e33b347b2ec2697567ed", "type": "github" }, "original": { @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1734090121, - "narHash": "sha256-pZkQJLvvhQUjDdBFlLzvu4Du1KJJmwyC4ndGMU1EZZc=", + "lastModified": 1735549217, + "narHash": "sha256-6j6OJgegiV0FKxQQ6a/ZFgd6QFlq/32dNM6KxM9kwbc=", "ref": "refs/heads/master", - "rev": "1531b6cc98f59e0e2cba4dac81b5a279101245f5", - "revCount": 1441, + "rev": "2f0847d77b428d5c38dcb0fbc7abb3724a202f52", + "revCount": 1453, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -117,11 +117,11 @@ ] }, "locked": { - "lastModified": 1733921114, - "narHash": "sha256-nx+Ot4EYQHLldVq3QQxHhQ+gI/BnBk/aLDHD8eDG2qE=", + "lastModified": 1734267097, + "narHash": "sha256-aWg7XDiOlWnkXfDbKrBn9ITR46/JXfndvYHxFJ1vN78=", "owner": "m-labs", "repo": "sipyco", - "rev": "aff9cbbf783b9d703affc5f818ebbc95615c2ea0", + "rev": "430978ada3fefe32de01f1b884b3031e48aaef96", "type": "github" }, "original": { @@ -133,11 +133,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1727677091, - "narHash": "sha256-Zg3SQnTwMM/VkOGKogbPyuCC2NhLy8HB2SPEUWWNgCU=", + "lastModified": 1735131698, + "narHash": "sha256-P4vaF+9iVekRAC2/mc9G7IwI6baBpPAxiDQ8uye4sAs=", "owner": "m-labs", "repo": "migen", - "rev": "c19ae9f8ae162ffe2d310a92bfce53ac2a821bc8", + "rev": "4c2ae8dfeea37f235b52acb8166f12acaaae4f7c", "type": "github" }, "original": { @@ -149,11 +149,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1729234629, - "narHash": "sha256-TLsTCXV5AC2xh+bS7EhBVBKqdqIU3eKrnlWcFF9LtAM=", + "lastModified": 1735531002, + "narHash": "sha256-7bKOe+Sh7gfVsAFM8slsj0+npVJTMKuZkk8sbNNm6wM=", "ref": "refs/heads/master", - "rev": "6085a312bca26adeca6584e37d08c8ba2e1d6e38", - "revCount": 2460, + "rev": "90cb18af8418233bc258caed875eaa9bdc79b71a", + "revCount": 2462, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From 644925e1170a8866c59855735a536737fb306de2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 4 Jan 2025 10:43:34 +0800 Subject: [PATCH 344/352] flake: update dependencies --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 8eb7c3fdf..aacf90341 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1735549217, - "narHash": "sha256-6j6OJgegiV0FKxQQ6a/ZFgd6QFlq/32dNM6KxM9kwbc=", + "lastModified": 1735957721, + "narHash": "sha256-Xs8RhMsDeeT+yJl2p4QKkof33prbv3bftlisEZON6Oc=", "ref": "refs/heads/master", - "rev": "2f0847d77b428d5c38dcb0fbc7abb3724a202f52", - "revCount": 1453, + "rev": "e480081e4b9d95831958c65721ed42d2d32e3989", + "revCount": 1479, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -63,11 +63,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1733940404, - "narHash": "sha256-Pj39hSoUA86ZePPF/UXiYHHM7hMIkios8TYG29kQT4g=", + "lastModified": 1735834308, + "narHash": "sha256-dklw3AXr3OGO4/XT1Tu3Xz9n/we8GctZZ75ZWVqAVhk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5d67ea6b4b63378b9c13be21e2ec9d1afc921713", + "rev": "6df24922a1400241dae323af55f30e4318a6ca65", "type": "github" }, "original": { From 0f98453d9376e8807e00b34415f8adeff2cd1b67 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Jan 2025 17:11:31 +0800 Subject: [PATCH 345/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index aacf90341..9c59c5427 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1735957721, - "narHash": "sha256-Xs8RhMsDeeT+yJl2p4QKkof33prbv3bftlisEZON6Oc=", + "lastModified": 1736153613, + "narHash": "sha256-0zivXAggwqhHUK7Uq10+bx2d/eS2KQ6RObOj/JeBzok=", "ref": "refs/heads/master", - "rev": "e480081e4b9d95831958c65721ed42d2d32e3989", - "revCount": 1479, + "rev": "eaaa194a87082ee5530f724b45c9822466aafe56", + "revCount": 1486, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From a6e8020eb1a1c4898443e281f1ab465ecd32c626 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 15 Jan 2025 21:37:12 +0800 Subject: [PATCH 346/352] flake: update dependencies --- flake.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/flake.lock b/flake.lock index 9c59c5427..3cac84440 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1736153613, - "narHash": "sha256-0zivXAggwqhHUK7Uq10+bx2d/eS2KQ6RObOj/JeBzok=", + "lastModified": 1736948038, + "narHash": "sha256-sxjUEvuJI9niglqmnS710mNTzzCaX9KJOpfVuHvCouw=", "ref": "refs/heads/master", - "rev": "eaaa194a87082ee5530f724b45c9822466aafe56", - "revCount": 1486, + "rev": "c15062ab4c1ff391b327b91f580b541f37cdde56", + "revCount": 1499, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -63,11 +63,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1735834308, - "narHash": "sha256-dklw3AXr3OGO4/XT1Tu3Xz9n/we8GctZZ75ZWVqAVhk=", + "lastModified": 1736798957, + "narHash": "sha256-qwpCtZhSsSNQtK4xYGzMiyEDhkNzOCz/Vfu4oL2ETsQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6df24922a1400241dae323af55f30e4318a6ca65", + "rev": "9abb87b552b7f55ac8916b6fc9e5cb486656a2f3", "type": "github" }, "original": { @@ -149,11 +149,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1735531002, - "narHash": "sha256-7bKOe+Sh7gfVsAFM8slsj0+npVJTMKuZkk8sbNNm6wM=", + "lastModified": 1736416570, + "narHash": "sha256-tbcN/fzejZIaYbTbwk8Ir1glYevESqMinMeDB3z8oxg=", "ref": "refs/heads/master", - "rev": "90cb18af8418233bc258caed875eaa9bdc79b71a", - "revCount": 2462, + "rev": "1f5318e9edc1085ac77e9b85b8f5e03371dba54c", + "revCount": 2464, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From 704efd6fd4a127d354a1035f27834ad08eaf9d8c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 21 Jan 2025 09:08:55 +0800 Subject: [PATCH 347/352] flake: update dependencies --- flake.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/flake.lock b/flake.lock index 3cac84440..b56122aed 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1736948038, - "narHash": "sha256-sxjUEvuJI9niglqmnS710mNTzzCaX9KJOpfVuHvCouw=", + "lastModified": 1737339848, + "narHash": "sha256-FXYsU4WIia9VbTnbWPWdHUP5UyRoNaJX4mBpmh92+2I=", "ref": "refs/heads/master", - "rev": "c15062ab4c1ff391b327b91f580b541f37cdde56", - "revCount": 1499, + "rev": "f817d3347bb4b385754141a50029ebf8e03a9912", + "revCount": 1511, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -133,11 +133,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1735131698, - "narHash": "sha256-P4vaF+9iVekRAC2/mc9G7IwI6baBpPAxiDQ8uye4sAs=", + "lastModified": 1737001477, + "narHash": "sha256-5Rv7R8OO/CsjdDreo+vCUO7dIrTD+70meV5rIvHOGDk=", "owner": "m-labs", "repo": "migen", - "rev": "4c2ae8dfeea37f235b52acb8166f12acaaae4f7c", + "rev": "28e913e7114dae485747ccd8f9fd436ada2195f0", "type": "github" }, "original": { @@ -149,11 +149,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1736416570, - "narHash": "sha256-tbcN/fzejZIaYbTbwk8Ir1glYevESqMinMeDB3z8oxg=", + "lastModified": 1737003761, + "narHash": "sha256-1sdkGLqB/484Bz6/Q19UmEQGueTrEldz2tg1F5DHXvY=", "ref": "refs/heads/master", - "rev": "1f5318e9edc1085ac77e9b85b8f5e03371dba54c", - "revCount": 2464, + "rev": "b3467ff0052f46fd4f15b31441e904b635777683", + "revCount": 2466, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From 963aeaeb9ae50e1b87af8412a5935bc63e91c19f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Feb 2025 15:44:06 +0800 Subject: [PATCH 348/352] flake: update dependencies --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index b56122aed..3612f198e 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1737339848, - "narHash": "sha256-FXYsU4WIia9VbTnbWPWdHUP5UyRoNaJX4mBpmh92+2I=", + "lastModified": 1738741343, + "narHash": "sha256-YwMpJaMXTfqym/8kgMUjmcbZd5JXakdwPfycWxaryUw=", "ref": "refs/heads/master", - "rev": "f817d3347bb4b385754141a50029ebf8e03a9912", - "revCount": 1511, + "rev": "c32c68b0b0823a21a4528262321dc4c1ebc4fde4", + "revCount": 1521, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -63,11 +63,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1736798957, - "narHash": "sha256-qwpCtZhSsSNQtK4xYGzMiyEDhkNzOCz/Vfu4oL2ETsQ=", + "lastModified": 1738680400, + "narHash": "sha256-ooLh+XW8jfa+91F1nhf9OF7qhuA/y1ChLx6lXDNeY5U=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9abb87b552b7f55ac8916b6fc9e5cb486656a2f3", + "rev": "799ba5bffed04ced7067a91798353d360788b30d", "type": "github" }, "original": { From 7c6d64417dd5f717346df2e7ba4d3c6f90caa467 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Feb 2025 16:39:55 +0800 Subject: [PATCH 349/352] flake: update dependencies --- flake.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/flake.lock b/flake.lock index 3612f198e..7c514193e 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1738741343, - "narHash": "sha256-YwMpJaMXTfqym/8kgMUjmcbZd5JXakdwPfycWxaryUw=", + "lastModified": 1739158198, + "narHash": "sha256-ucND9k+z6AbC1ZjCtxpXDQzWbCaLYh94JVA2k5UZo3E=", "ref": "refs/heads/master", - "rev": "c32c68b0b0823a21a4528262321dc4c1ebc4fde4", - "revCount": 1521, + "rev": "064aa0411f678bd40fe8acdeffd3cad71894e1b5", + "revCount": 1534, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, @@ -133,11 +133,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1737001477, - "narHash": "sha256-5Rv7R8OO/CsjdDreo+vCUO7dIrTD+70meV5rIvHOGDk=", + "lastModified": 1738906518, + "narHash": "sha256-GproDJowtcgbccsT+I0mObzFhE483shcS8MSszKXwlc=", "owner": "m-labs", "repo": "migen", - "rev": "28e913e7114dae485747ccd8f9fd436ada2195f0", + "rev": "2828df54594673653a641ab551caf6c6b1bfeee5", "type": "github" }, "original": { @@ -149,11 +149,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1737003761, - "narHash": "sha256-1sdkGLqB/484Bz6/Q19UmEQGueTrEldz2tg1F5DHXvY=", + "lastModified": 1738745832, + "narHash": "sha256-mPZs3J3hIk5XJthhHX56bUY1kyGb/kHg9ZlSHWanpXA=", "ref": "refs/heads/master", - "rev": "b3467ff0052f46fd4f15b31441e904b635777683", - "revCount": 2466, + "rev": "3529bddf5c950985532d27a3dbc907cfe42d7b48", + "revCount": 2472, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From d13f3f4a13f975afbe2ce7ef29925be5bc5b3865 Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 10 Feb 2025 11:06:58 +0800 Subject: [PATCH 350/352] language: report special python IDs --- artiq/coredevice/core.py | 1 + artiq/language/core.py | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 0bad68ba1..d74e46a10 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -109,6 +109,7 @@ class Core: self.compiler.analyze( core_language._registered_functions, core_language._registered_classes, + core_language._special_ids, core_language._registered_modules ) self.analyzed = True diff --git a/artiq/language/core.py b/artiq/language/core.py index 7e970e420..b6a6491a5 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -227,6 +227,12 @@ parallel = _ParallelContextManager() legacy_parallel = _ParallelContextManager() sequential = _SequentialContextManager() +_special_ids = { + "parallel": id(parallel), + "legacy_parallel": id(legacy_parallel), + "sequential": id(sequential), +} + def delay_mu(duration): """Increases the RTIO time by the given amount (in machine units).""" From 554b0749ca5985bf4d006c4f29a05e83de0a226d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Feb 2025 16:46:37 +0800 Subject: [PATCH 351/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 7c514193e..0c811f2d5 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1739158198, - "narHash": "sha256-ucND9k+z6AbC1ZjCtxpXDQzWbCaLYh94JVA2k5UZo3E=", + "lastModified": 1739176969, + "narHash": "sha256-rpe+zy7gOegoYwg2vTh+EEhS4CcNwhKS97GqsYjGR+c=", "ref": "refs/heads/master", - "rev": "064aa0411f678bd40fe8acdeffd3cad71894e1b5", - "revCount": 1534, + "rev": "715dc71396675d6fd9951b911a7677e482a78a38", + "revCount": 1535, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" }, From 0d826057906b0bb9a110e168d11d4585c05d46b8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Feb 2025 16:54:06 +0800 Subject: [PATCH 352/352] flake: update nac3 --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 0c811f2d5..22135de89 100644 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1739176969, - "narHash": "sha256-rpe+zy7gOegoYwg2vTh+EEhS4CcNwhKS97GqsYjGR+c=", + "lastModified": 1739177615, + "narHash": "sha256-JuP4B91xgKgg+/yAdjr8D+eDT1IV7WszbV+bpu1xvQ8=", "ref": "refs/heads/master", - "rev": "715dc71396675d6fd9951b911a7677e482a78a38", - "revCount": 1535, + "rev": "82a580c5c6e68e0c8f92ecd44da2a18b1adf7d0a", + "revCount": 1536, "type": "git", "url": "https://git.m-labs.hk/m-labs/nac3.git" },