From 798a5f70df9a9f7f486a71152ddf6ee572e3d9cc Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 8 Nov 2016 11:53:26 +0000 Subject: [PATCH 01/47] Revert "runtime: remove some redundant libm functions copied inline." This reverts commit fee75bd50f9240b7b0377291718d7354498c9b62. LLVM does not have lround as a libcall and this inhibits LICM. --- .../compiler/transforms/llvm_ir_generator.py | 9 +++--- artiq/runtime.rs/libksupport/api.rs | 2 +- artiq/runtime/ksupport_glue.c | 29 +++++++++++++++++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index e9643aa04..c86888a0f 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -323,6 +323,8 @@ class LLVMIRGenerator: 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": @@ -347,8 +349,6 @@ class LLVMIRGenerator: llty = ll.FunctionType(lli32, [llptr]) elif name == "strcmp": llty = ll.FunctionType(lli32, [llptr, llptr]) - elif name == "lround": - llty = ll.FunctionType(lli32, [lldouble]) elif name == "send_rpc": llty = ll.FunctionType(llvoid, [lli32, llptr, llptrptr]) elif name == "send_async_rpc": @@ -1044,8 +1044,9 @@ class LLVMIRGenerator: name=insn.name) elif insn.op == "round": llarg = self.map(insn.operands[0]) - return self.llbuilder.call(self.llbuiltin("lround"), [llarg], - name=insn.name) + 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: diff --git a/artiq/runtime.rs/libksupport/api.rs b/artiq/runtime.rs/libksupport/api.rs index 81c4d75df..5f9d7f967 100644 --- a/artiq/runtime.rs/libksupport/api.rs +++ b/artiq/runtime.rs/libksupport/api.rs @@ -74,7 +74,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ /* libm */ api!(sqrt), - api!(lround), + api!(round), /* exceptions */ api!(_Unwind_Resume), diff --git a/artiq/runtime/ksupport_glue.c b/artiq/runtime/ksupport_glue.c index 515635c94..f0d496dc3 100644 --- a/artiq/runtime/ksupport_glue.c +++ b/artiq/runtime/ksupport_glue.c @@ -70,10 +70,33 @@ int dl_iterate_phdr (int (*callback)(struct dl_phdr_info *, size_t, void *), voi } /* called by kernel */ -long lround(double x); -long lround(double x) +double round(double x); +double round(double x) { - return x < 0 ? floor(x) : ceil(x); + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double y; + + if (e >= 0x3ff+52) + return x; + if (u.i >> 63) + x = -x; + if (e < 0x3ff-1) { + /* we don't do it in ARTIQ */ + /* raise inexact if x!=0 */ + // FORCE_EVAL(x + 0x1p52); + return 0*u.f; + } + y = (double)(x + 0x1p52) - 0x1p52 - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i >> 63) + y = -y; + return y; } /* called by kernel */ From 0d7688017bfdd7116fcedd71da3e9b488fdcd165 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 7 Nov 2016 09:31:43 +0000 Subject: [PATCH 02/47] Revert "Revert "Update for LLVM 3.9."" This reverts commit 5f5975844a6af08639250d689d3f78bf213b8508. --- artiq/compiler/targets.py | 5 +-- .../compiler/transforms/llvm_ir_generator.py | 38 +++++++++---------- conda/artiq/meta.yaml | 2 +- 3 files changed, 19 insertions(+), 26 deletions(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index aab813737..0fd2aa0fe 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -86,14 +86,11 @@ class Target: llmachine = lltarget.create_target_machine( features=",".join(["+{}".format(f) for f in self.features]), reloc="pic", codemodel="default") - llmachine.set_verbose(True) + llmachine.set_asm_verbosity(True) return llmachine def optimize(self, llmodule): - llmachine = self.target_machine() llpassmgr = llvm.create_module_pass_manager() - llmachine.target_data.add_pass(llpassmgr) - llmachine.add_analysis_passes(llpassmgr) # Register our alias analysis passes. llpassmgr.add_basic_alias_analysis_pass() diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index c86888a0f..b99c6ed3b 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -37,9 +37,16 @@ def memoize(generator): class DebugInfoEmitter: def __init__(self, llmodule): self.llmodule = llmodule - self.llsubprograms = [] + self.llcompileunit = None self.cache = {} + llident = self.llmodule.add_named_metadata('llvm.ident') + llident.add(self.emit_metadata(["ARTIQ"])) + + llflags = self.llmodule.add_named_metadata('llvm.module.flags') + llflags.add(self.emit_metadata([2, "Debug Info Version", 3])) + llflags.add(self.emit_metadata([2, "Dwarf Version", 4])) + def emit_metadata(self, operands): def map_operand(operand): if operand is None: @@ -67,14 +74,13 @@ class DebugInfoEmitter: }) @memoize - def emit_compile_unit(self, source_buffer, llsubprograms): + def emit_compile_unit(self, source_buffer): return self.emit_debug_info("DICompileUnit", { "language": ll.DIToken("DW_LANG_Python"), "file": self.emit_file(source_buffer), "producer": "ARTIQ", "runtimeVersion": 0, "emissionKind": 2, # full=1, lines only=2 - "subprograms": self.emit_metadata(llsubprograms) }, is_distinct=True) @memoize @@ -86,21 +92,26 @@ class DebugInfoEmitter: @memoize def emit_subprogram(self, func, llfunc): source_buffer = func.loc.source_buffer + + if self.llcompileunit is None: + self.llcompileunit = self.emit_compile_unit(source_buffer) + llcompileunits = self.llmodule.add_named_metadata('llvm.dbg.cu') + llcompileunits.add(self.llcompileunit) + display_name = "{}{}".format(func.name, types.TypePrinter().name(func.type)) - llsubprogram = self.emit_debug_info("DISubprogram", { + return self.emit_debug_info("DISubprogram", { "name": func.name, "linkageName": llfunc.name, "type": self.emit_subroutine_type(func.type), "file": self.emit_file(source_buffer), "line": func.loc.line(), + "unit": self.llcompileunit, "scope": self.emit_file(source_buffer), "scopeLine": func.loc.line(), "isLocal": func.is_internal, "isDefinition": True, "variables": self.emit_metadata([]) }, is_distinct=True) - self.llsubprograms.append(llsubprogram) - return llsubprogram @memoize def emit_loc(self, loc, scope): @@ -110,18 +121,6 @@ class DebugInfoEmitter: "scope": scope }) - def finalize(self, source_buffer): - llident = self.llmodule.add_named_metadata('llvm.ident') - llident.add(self.emit_metadata(["ARTIQ"])) - - llflags = self.llmodule.add_named_metadata('llvm.module.flags') - llflags.add(self.emit_metadata([2, "Debug Info Version", 3])) - llflags.add(self.emit_metadata([2, "Dwarf Version", 4])) - - llcompile_units = self.llmodule.add_named_metadata('llvm.dbg.cu') - llcompile_units.add(self.emit_compile_unit(source_buffer, tuple(self.llsubprograms))) - - class LLVMIRGenerator: def __init__(self, engine, module_name, target, embedding_map): self.engine = engine @@ -410,9 +409,6 @@ class LLVMIRGenerator: for func in functions: self.process_function(func) - if any(functions): - self.debug_info_emitter.finalize(functions[0].loc.source_buffer) - if attribute_writeback and self.embedding_map is not None: self.emit_attribute_writeback() diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index ca300b8d3..f2cc0aeea 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -18,7 +18,7 @@ requirements: - binutils-or1k-linux run: - python >=3.5.2 - - llvmlite-artiq 0.10.0.dev py35_24 + - llvmlite-artiq 0.11.0.dev py35_25 - lit - outputcheck - scipy From e0297039c9de975336aff3a74e4f58c8fcc2c9d5 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 8 Nov 2016 12:08:20 +0000 Subject: [PATCH 03/47] artiq_run: fix bitrot in .ll/.bc runners. --- artiq/frontend/artiq_run.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index 4972a5cd7..004171a0f 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -73,8 +73,7 @@ class LLVMIRRunner(FileRunner): with open(self.file, "r") as f: llmodule = llvm.parse_assembly(f.read()) llmodule.verify() - return self.target.link([self.target.assemble(llmodule)], - init_fn="__modinit__") + return self.target.link([self.target.assemble(llmodule)]) class LLVMBitcodeRunner(FileRunner): @@ -82,8 +81,7 @@ class LLVMBitcodeRunner(FileRunner): with open(self.file, "rb") as f: llmodule = llvm.parse_bitcode(f.read()) llmodule.verify() - return self.target.link([self.target.assemble(llmodule)], - init_fn="__modinit__") + return self.target.link([self.target.assemble(llmodule)]) class DummyScheduler: From a8fd697d41a1e34b07b5132b6ccad8671777287c Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 8 Nov 2016 12:57:06 +0000 Subject: [PATCH 04/47] runtime: unbreak 453e8b7. Running rustc --cfg 'foo="1"' does not result in a statement of the form do_thing() to be compilex in. --- artiq/runtime.rs/libksupport/api.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/runtime.rs/libksupport/api.rs b/artiq/runtime.rs/libksupport/api.rs index 5f9d7f967..b9788be26 100644 --- a/artiq/runtime.rs/libksupport/api.rs +++ b/artiq/runtime.rs/libksupport/api.rs @@ -105,15 +105,15 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(rtio_input_timestamp), api!(rtio_input_data), - #[cfg(rtio_dds_count)] + #[cfg(has_rtio_dds_count)] api!(dds_init), - #[cfg(rtio_dds_count)] + #[cfg(has_rtio_dds_count)] api!(dds_init_sync), - #[cfg(rtio_dds_count)] + #[cfg(has_rtio_dds_count)] api!(dds_batch_enter), - #[cfg(rtio_dds_count)] + #[cfg(has_rtio_dds_count)] api!(dds_batch_exit), - #[cfg(rtio_dds_count)] + #[cfg(has_rtio_dds_count)] api!(dds_set), api!(i2c_init), From 7b81ed1d1851ce12a047cf3d8e61167271b83b8d Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 8 Nov 2016 12:58:20 +0000 Subject: [PATCH 05/47] Revert "Revert "Revert "Update for LLVM 3.9.""" This reverts commit 0d7688017bfdd7116fcedd71da3e9b488fdcd165. --- artiq/compiler/targets.py | 5 ++- .../compiler/transforms/llvm_ir_generator.py | 38 ++++++++++--------- conda/artiq/meta.yaml | 2 +- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index 0fd2aa0fe..aab813737 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -86,11 +86,14 @@ class Target: llmachine = lltarget.create_target_machine( features=",".join(["+{}".format(f) for f in self.features]), reloc="pic", codemodel="default") - llmachine.set_asm_verbosity(True) + llmachine.set_verbose(True) return llmachine def optimize(self, llmodule): + llmachine = self.target_machine() llpassmgr = llvm.create_module_pass_manager() + llmachine.target_data.add_pass(llpassmgr) + llmachine.add_analysis_passes(llpassmgr) # Register our alias analysis passes. llpassmgr.add_basic_alias_analysis_pass() diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index b99c6ed3b..c86888a0f 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -37,16 +37,9 @@ def memoize(generator): class DebugInfoEmitter: def __init__(self, llmodule): self.llmodule = llmodule - self.llcompileunit = None + self.llsubprograms = [] self.cache = {} - llident = self.llmodule.add_named_metadata('llvm.ident') - llident.add(self.emit_metadata(["ARTIQ"])) - - llflags = self.llmodule.add_named_metadata('llvm.module.flags') - llflags.add(self.emit_metadata([2, "Debug Info Version", 3])) - llflags.add(self.emit_metadata([2, "Dwarf Version", 4])) - def emit_metadata(self, operands): def map_operand(operand): if operand is None: @@ -74,13 +67,14 @@ class DebugInfoEmitter: }) @memoize - def emit_compile_unit(self, source_buffer): + def emit_compile_unit(self, source_buffer, llsubprograms): return self.emit_debug_info("DICompileUnit", { "language": ll.DIToken("DW_LANG_Python"), "file": self.emit_file(source_buffer), "producer": "ARTIQ", "runtimeVersion": 0, "emissionKind": 2, # full=1, lines only=2 + "subprograms": self.emit_metadata(llsubprograms) }, is_distinct=True) @memoize @@ -92,26 +86,21 @@ class DebugInfoEmitter: @memoize def emit_subprogram(self, func, llfunc): source_buffer = func.loc.source_buffer - - if self.llcompileunit is None: - self.llcompileunit = self.emit_compile_unit(source_buffer) - llcompileunits = self.llmodule.add_named_metadata('llvm.dbg.cu') - llcompileunits.add(self.llcompileunit) - display_name = "{}{}".format(func.name, types.TypePrinter().name(func.type)) - return self.emit_debug_info("DISubprogram", { + llsubprogram = self.emit_debug_info("DISubprogram", { "name": func.name, "linkageName": llfunc.name, "type": self.emit_subroutine_type(func.type), "file": self.emit_file(source_buffer), "line": func.loc.line(), - "unit": self.llcompileunit, "scope": self.emit_file(source_buffer), "scopeLine": func.loc.line(), "isLocal": func.is_internal, "isDefinition": True, "variables": self.emit_metadata([]) }, is_distinct=True) + self.llsubprograms.append(llsubprogram) + return llsubprogram @memoize def emit_loc(self, loc, scope): @@ -121,6 +110,18 @@ class DebugInfoEmitter: "scope": scope }) + def finalize(self, source_buffer): + llident = self.llmodule.add_named_metadata('llvm.ident') + llident.add(self.emit_metadata(["ARTIQ"])) + + llflags = self.llmodule.add_named_metadata('llvm.module.flags') + llflags.add(self.emit_metadata([2, "Debug Info Version", 3])) + llflags.add(self.emit_metadata([2, "Dwarf Version", 4])) + + llcompile_units = self.llmodule.add_named_metadata('llvm.dbg.cu') + llcompile_units.add(self.emit_compile_unit(source_buffer, tuple(self.llsubprograms))) + + class LLVMIRGenerator: def __init__(self, engine, module_name, target, embedding_map): self.engine = engine @@ -409,6 +410,9 @@ class LLVMIRGenerator: for func in functions: self.process_function(func) + if any(functions): + self.debug_info_emitter.finalize(functions[0].loc.source_buffer) + if attribute_writeback and self.embedding_map is not None: self.emit_attribute_writeback() diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index f2cc0aeea..ca300b8d3 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -18,7 +18,7 @@ requirements: - binutils-or1k-linux run: - python >=3.5.2 - - llvmlite-artiq 0.11.0.dev py35_25 + - llvmlite-artiq 0.10.0.dev py35_24 - lit - outputcheck - scipy From ec8fe6f8bd858b8bd2a9595f317a6ede52dced7b Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 8 Nov 2016 14:22:47 +0000 Subject: [PATCH 06/47] Revert "Revert "Revert "Revert "Update for LLVM 3.9."""" This reverts commit 7b81ed1d1851ce12a047cf3d8e61167271b83b8d. --- artiq/compiler/targets.py | 5 +-- .../compiler/transforms/llvm_ir_generator.py | 38 +++++++++---------- conda/artiq/meta.yaml | 2 +- 3 files changed, 19 insertions(+), 26 deletions(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index aab813737..0fd2aa0fe 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -86,14 +86,11 @@ class Target: llmachine = lltarget.create_target_machine( features=",".join(["+{}".format(f) for f in self.features]), reloc="pic", codemodel="default") - llmachine.set_verbose(True) + llmachine.set_asm_verbosity(True) return llmachine def optimize(self, llmodule): - llmachine = self.target_machine() llpassmgr = llvm.create_module_pass_manager() - llmachine.target_data.add_pass(llpassmgr) - llmachine.add_analysis_passes(llpassmgr) # Register our alias analysis passes. llpassmgr.add_basic_alias_analysis_pass() diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index c86888a0f..b99c6ed3b 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -37,9 +37,16 @@ def memoize(generator): class DebugInfoEmitter: def __init__(self, llmodule): self.llmodule = llmodule - self.llsubprograms = [] + self.llcompileunit = None self.cache = {} + llident = self.llmodule.add_named_metadata('llvm.ident') + llident.add(self.emit_metadata(["ARTIQ"])) + + llflags = self.llmodule.add_named_metadata('llvm.module.flags') + llflags.add(self.emit_metadata([2, "Debug Info Version", 3])) + llflags.add(self.emit_metadata([2, "Dwarf Version", 4])) + def emit_metadata(self, operands): def map_operand(operand): if operand is None: @@ -67,14 +74,13 @@ class DebugInfoEmitter: }) @memoize - def emit_compile_unit(self, source_buffer, llsubprograms): + def emit_compile_unit(self, source_buffer): return self.emit_debug_info("DICompileUnit", { "language": ll.DIToken("DW_LANG_Python"), "file": self.emit_file(source_buffer), "producer": "ARTIQ", "runtimeVersion": 0, "emissionKind": 2, # full=1, lines only=2 - "subprograms": self.emit_metadata(llsubprograms) }, is_distinct=True) @memoize @@ -86,21 +92,26 @@ class DebugInfoEmitter: @memoize def emit_subprogram(self, func, llfunc): source_buffer = func.loc.source_buffer + + if self.llcompileunit is None: + self.llcompileunit = self.emit_compile_unit(source_buffer) + llcompileunits = self.llmodule.add_named_metadata('llvm.dbg.cu') + llcompileunits.add(self.llcompileunit) + display_name = "{}{}".format(func.name, types.TypePrinter().name(func.type)) - llsubprogram = self.emit_debug_info("DISubprogram", { + return self.emit_debug_info("DISubprogram", { "name": func.name, "linkageName": llfunc.name, "type": self.emit_subroutine_type(func.type), "file": self.emit_file(source_buffer), "line": func.loc.line(), + "unit": self.llcompileunit, "scope": self.emit_file(source_buffer), "scopeLine": func.loc.line(), "isLocal": func.is_internal, "isDefinition": True, "variables": self.emit_metadata([]) }, is_distinct=True) - self.llsubprograms.append(llsubprogram) - return llsubprogram @memoize def emit_loc(self, loc, scope): @@ -110,18 +121,6 @@ class DebugInfoEmitter: "scope": scope }) - def finalize(self, source_buffer): - llident = self.llmodule.add_named_metadata('llvm.ident') - llident.add(self.emit_metadata(["ARTIQ"])) - - llflags = self.llmodule.add_named_metadata('llvm.module.flags') - llflags.add(self.emit_metadata([2, "Debug Info Version", 3])) - llflags.add(self.emit_metadata([2, "Dwarf Version", 4])) - - llcompile_units = self.llmodule.add_named_metadata('llvm.dbg.cu') - llcompile_units.add(self.emit_compile_unit(source_buffer, tuple(self.llsubprograms))) - - class LLVMIRGenerator: def __init__(self, engine, module_name, target, embedding_map): self.engine = engine @@ -410,9 +409,6 @@ class LLVMIRGenerator: for func in functions: self.process_function(func) - if any(functions): - self.debug_info_emitter.finalize(functions[0].loc.source_buffer) - if attribute_writeback and self.embedding_map is not None: self.emit_attribute_writeback() diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index ca300b8d3..f2cc0aeea 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -18,7 +18,7 @@ requirements: - binutils-or1k-linux run: - python >=3.5.2 - - llvmlite-artiq 0.10.0.dev py35_24 + - llvmlite-artiq 0.11.0.dev py35_25 - lit - outputcheck - scipy From 99ad9b591796414f1fe550ccf928a2626a92536d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 8 Nov 2016 23:33:03 +0800 Subject: [PATCH 07/47] add has_dds, use config flags --- artiq/gateware/targets/kc705.py | 12 +++++++----- artiq/gateware/targets/pipistrello.py | 3 ++- artiq/runtime.rs/libksupport/api.rs | 10 +++++----- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index ea38273d4..486f047f0 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -137,6 +137,8 @@ class _NIST_Ions(MiniSoC, AMPSoC): self.register_kernel_cpu_csrdevice("i2c") self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_DDS"] = None + def add_rtio(self, rtio_channels): self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) self.csr_devices.append("rtio_crg") @@ -198,7 +200,7 @@ class NIST_QC1(_NIST_Ions): self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels) self.config["RTIO_DDS_COUNT"] = 1 self.config["DDS_CHANNELS_PER_BUS"] = 8 - self.config["DDS_AD9858"] = True + self.config["DDS_AD9858"] = None phy = dds.AD9858(platform.request("dds"), 8) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, @@ -272,8 +274,8 @@ class NIST_CLOCK(_NIST_Ions): self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels) self.config["RTIO_DDS_COUNT"] = 1 self.config["DDS_CHANNELS_PER_BUS"] = 11 - self.config["DDS_AD9914"] = True - self.config["DDS_ONEHOT_SEL"] = True + self.config["DDS_AD9914"] = None + self.config["DDS_ONEHOT_SEL"] = None phy = dds.AD9914(platform.request("dds"), 11, onehot=True) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, @@ -350,8 +352,8 @@ class NIST_QC2(_NIST_Ions): self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels) self.config["RTIO_DDS_COUNT"] = 2 self.config["DDS_CHANNELS_PER_BUS"] = 12 - self.config["DDS_AD9914"] = True - self.config["DDS_ONEHOT_SEL"] = True + self.config["DDS_AD9914"] = None + self.config["DDS_ONEHOT_SEL"] = None for backplane_offset in range(2): phy = dds.AD9914( platform.request("dds", backplane_offset), 12, onehot=True) diff --git a/artiq/gateware/targets/pipistrello.py b/artiq/gateware/targets/pipistrello.py index f9afa683b..a0a5f0134 100755 --- a/artiq/gateware/targets/pipistrello.py +++ b/artiq/gateware/targets/pipistrello.py @@ -206,10 +206,11 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd rtio_channels.append(rtio.Channel.from_phy( phy, ofifo_depth=64, ififo_depth=64)) + self.config["HAS_DDS"] = None self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels) self.config["RTIO_DDS_COUNT"] = 1 self.config["DDS_CHANNELS_PER_BUS"] = 8 - self.config["DDS_AD9858"] = True + self.config["DDS_AD9858"] = None dds_pins = platform.request("dds") self.comb += dds_pins.p.eq(0) phy = dds.AD9858(dds_pins, 8) diff --git a/artiq/runtime.rs/libksupport/api.rs b/artiq/runtime.rs/libksupport/api.rs index b9788be26..f30b099b0 100644 --- a/artiq/runtime.rs/libksupport/api.rs +++ b/artiq/runtime.rs/libksupport/api.rs @@ -105,15 +105,15 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(rtio_input_timestamp), api!(rtio_input_data), - #[cfg(has_rtio_dds_count)] + #[cfg(has_dds)] api!(dds_init), - #[cfg(has_rtio_dds_count)] + #[cfg(has_dds)] api!(dds_init_sync), - #[cfg(has_rtio_dds_count)] + #[cfg(has_dds)] api!(dds_batch_enter), - #[cfg(has_rtio_dds_count)] + #[cfg(has_dds)] api!(dds_batch_exit), - #[cfg(has_rtio_dds_count)] + #[cfg(has_dds)] api!(dds_set), api!(i2c_init), From 124b257e05c711b3d6bec8fd7cca5717f11b668b Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 8 Nov 2016 22:08:04 +0000 Subject: [PATCH 08/47] conda: update for LLVM 3.9. --- conda/artiq/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index f2cc0aeea..de54eeec5 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -18,7 +18,7 @@ requirements: - binutils-or1k-linux run: - python >=3.5.2 - - llvmlite-artiq 0.11.0.dev py35_25 + - llvmlite-artiq 0.12.0.dev py35_27 - lit - outputcheck - scipy From bfbdba92057c021f1876db004e5851ac2b991918 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 8 Nov 2016 01:05:27 +0000 Subject: [PATCH 09/47] compiler: Emit all-kernel_invariant objects as LLVM constants This enables constant propagation optimisations, as verified by the included test case. This is only a first stop-gap measure, though; we should support optimisation based on kernel invariants on a more fine-grained level. --- .../compiler/transforms/llvm_ir_generator.py | 4 +++ .../lit/embedding/invariant_propagation.py | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 artiq/test/lit/embedding/invariant_propagation.py diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index b99c6ed3b..1095c2e64 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1384,6 +1384,7 @@ class LLVMIRGenerator: def _quote_attributes(): llglobal = None llfields = [] + emit_as_constant = True for attr in typ.attributes: if attr == "__objectid__": objectid = self.embedding_map.store_object(value) @@ -1404,6 +1405,8 @@ class LLVMIRGenerator: not types.is_c_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) @@ -1411,6 +1414,7 @@ class LLVMIRGenerator: 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 diff --git a/artiq/test/lit/embedding/invariant_propagation.py b/artiq/test/lit/embedding/invariant_propagation.py new file mode 100644 index 000000000..e1af5c9c1 --- /dev/null +++ b/artiq/test/lit/embedding/invariant_propagation.py @@ -0,0 +1,26 @@ +# 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() From eee8d0539885ebee609a94ce16a49ce092c77f8e Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 9 Nov 2016 14:59:57 +0000 Subject: [PATCH 10/47] doc: clarify kernel_invariant doc (fixes #609). --- doc/manual/compiler.rst | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/doc/manual/compiler.rst b/doc/manual/compiler.rst index 8185b2611..02c56e516 100644 --- a/doc/manual/compiler.rst +++ b/doc/manual/compiler.rst @@ -54,7 +54,7 @@ If an RPC returns no value, it can be invoked in a way that does not block until execution, but only until it is queued. (Submitting asynchronous RPCs too rapidly, as well as submitting asynchronous RPCs with arguments that are too large, can still block until completion.) -To define an asynchronous RPC, use the ``@rpc`` annotation with a flag: +To define an asynchronous RPC, use the ``@rpc`` annotation with a flag: :: @rpc(flags={"async"}) def record_result(x): @@ -87,7 +87,7 @@ Kernel invariants The compiler attempts to remove or hoist out of loops any redundant memory load operations, as well as propagate known constants into function bodies, which can enable further optimization. However, it must make conservative assumptions about code that it is unable to observe, because such code can change the value of the attribute, making the optimization invalid. -When an attribute is known to never change while the kernel is running, it can be marked as a *kernel invariant* to enable more aggressive optimization for this specific attribute: :: +When an attribute is known to never change while the kernel is running, it can be marked as a *kernel invariant* to enable more aggressive optimization for this specific attribute. :: class Converter: kernel_invariants = {"ratio"} @@ -99,4 +99,32 @@ When an attribute is known to never change while the kernel is running, it can b def convert(self, value): return value * self.ratio ** 2 -In the synthetic example above, the compiler will be able to detect that the result of evaluating ``self.ratio ** 2`` never changes and replace it with a constant, removing an expensive floating-point operation. +In the synthetic example above, the compiler will be able to detect that the result of evaluating ``self.ratio ** 2`` never changes and replace it with a constant, removing an expensive floating-point operation. :: + + class Worker: + kernel_invariants = {"interval"} + + def __init__(self, interval=1.0*us): + self.interval = interval + + def work(self): + # something useful + + class Looper: + def __init__(self, worker): + self.worker = worker + + @kernel + def loop(self): + for _ in range(100): + delay(self.worker.interval / 5.0) + self.worker.work() + +In the synthetic example above, the compiler will be able to detect that the result of evaluating ``self.interval / 5.0`` never changes, even though it neither knows the value of ``self.worker.interval`` beforehand nor can it see through the ``self.worker.work()`` function call, and hoist the expensive floating-point division out of the loop, transforming the code for ``loop`` into an equivalent of the following: :: + + @kernel + def loop(self): + precomputed_delay_mu = seconds_to_mu(self.worker.interval / 5.0) + for _ in range(100): + delay_mu(precomputed_delay_mu) + self.worker.work() From 71f1d388600573d3d36f1995cc076e7b6bd81b94 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 9 Nov 2016 15:10:53 +0000 Subject: [PATCH 11/47] conda: tighten pythonparser dependency (fixes #600). --- conda/artiq/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index de54eeec5..7d3491235 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -37,7 +37,7 @@ requirements: - pygit2 - aiohttp - binutils-or1k-linux - - pythonparser + - pythonparser 0.0 py_6 - levenshtein test: From 67e743d74a15425a224162363e27bba8cc66f459 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 9 Nov 2016 15:19:27 +0000 Subject: [PATCH 12/47] conda: use pythonparser 1.0. --- conda/artiq/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 7d3491235..05ac59ceb 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -37,7 +37,7 @@ requirements: - pygit2 - aiohttp - binutils-or1k-linux - - pythonparser 0.0 py_6 + - pythonparser 1.0 - levenshtein test: From 0e76cbc4147e61f4405a64768428be6d136786af Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 10 Nov 2016 01:04:36 +0000 Subject: [PATCH 13/47] artiq_compile: actually disable attribute writeback. I wrote both halves of this condition but forgot to hook them together. Fixes #586. --- artiq/compiler/module.py | 6 ++++-- artiq/coredevice/core.py | 6 ++++-- artiq/frontend/artiq_compile.py | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py index 0e07a5b60..e169a656e 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -40,7 +40,8 @@ class Source: return cls(source.Buffer(f.read(), filename, 1), engine=engine) class Module: - def __init__(self, src, ref_period=1e-6): + def __init__(self, src, ref_period=1e-6, attribute_writeback=True): + self.attribute_writeback = attribute_writeback self.engine = src.engine self.embedding_map = src.embedding_map self.name = src.name @@ -79,7 +80,8 @@ class Module: 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=True) + return llvm_ir_generator.process(self.artiq_ir, + attribute_writeback=self.attribute_writeback) def __repr__(self): printer = types.TypePrinter() diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 1b1b7b3a4..58c2ca7a9 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -81,7 +81,7 @@ class Core: self.core = self self.comm.core = self - def compile(self, function, args, kwargs, set_result=None, with_attr_writeback=True): + def compile(self, function, args, kwargs, set_result=None, attribute_writeback=True): try: engine = _DiagnosticEngine(all_errors_are_fatal=True) @@ -89,7 +89,9 @@ class Core: stitcher.stitch_call(function, args, kwargs, set_result) stitcher.finalize() - module = Module(stitcher, ref_period=self.ref_period) + module = Module(stitcher, + ref_period=self.ref_period, + attribute_writeback=attribute_writeback) target = OR1KTarget() library = target.compile_and_link([module]) diff --git a/artiq/frontend/artiq_compile.py b/artiq/frontend/artiq_compile.py index 16d211399..ef801516c 100755 --- a/artiq/frontend/artiq_compile.py +++ b/artiq/frontend/artiq_compile.py @@ -55,7 +55,7 @@ def main(): object_map, kernel_library, _, _ = \ core.compile(exp.run, [exp_inst], {}, - with_attr_writeback=False) + attribute_writeback=False) except CompileError as error: return finally: From 3b6cbb1f063035bb5e24724827666c6b15fe0a9d Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 10 Nov 2016 20:25:15 +0000 Subject: [PATCH 14/47] artiq_devtool: implement. --- artiq/frontend/artiq_devtool.py | 144 ++++++++++++++++++++++++++++++++ setup.py | 2 + 2 files changed, 146 insertions(+) create mode 100644 artiq/frontend/artiq_devtool.py diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py new file mode 100644 index 000000000..4c6aba681 --- /dev/null +++ b/artiq/frontend/artiq_devtool.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3.5 + +# This script makes the following assumptions: +# * miniconda is installed remotely at ~/miniconda +# * misoc and artiq are installed remotely via conda + +import sys +import argparse +import subprocess +import socket +import select +import threading +import paramiko + +from artiq.tools import verbosity_args, init_logger, logger +from random import Random + + +def get_argparser(): + parser = argparse.ArgumentParser(description="ARTIQ core device " + "development tool") + + verbosity_args(parser) + + parser.add_argument("--host", nargs=1, metavar="HOST", + type=str, default="lab.m-labs.hk", + help="SSH host where the development board is located") + parser.add_argument("--serial", nargs=1, metavar="SERIAL", + type=str, default="/dev/ttyUSB0", + help="TTY device corresponding to the development board") + parser.add_argument("--ip", nargs=1, metavar="IP", + type=str, default="kc705.lab.m-labs.hk", + help="IP address corresponding to the development board") + + parser.add_argument("actions", metavar="ACTION", + type=str, default=[], nargs="+", + help="actions to perform (sequence of: build boot connect)") + + return parser + + +def main(): + args = get_argparser().parse_args() + init_logger(args) + + ssh = None + def get_ssh(): + nonlocal ssh + if ssh is not None: + return ssh + ssh = paramiko.SSHClient() + ssh.load_system_host_keys() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(args.host) + return ssh + + sftp = None + def get_sftp(): + nonlocal sftp + if sftp is not None: + return sftp + sftp = get_ssh().open_sftp() + return sftp + + rng = Random() + tmp = "artiq" + "".join([rng.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ") for _ in range(6)]) + env = "bash -c 'export PATH=$HOME/miniconda/bin:$PATH; exec $0 $*' " + + def run_command(cmd): + logger.info("Executing {}".format(cmd)) + chan = get_ssh().get_transport().open_session() + chan.set_combine_stderr(True) + chan.exec_command(cmd.format(tmp=tmp, env=env, serial=args.serial, ip=args.ip)) + return chan.makefile() + + def drain(chan): + while True: + char = chan.read(1) + if char == b"": + break + sys.stderr.write(char.decode("utf-8")) + + for action in args.actions: + if action == "build": + logger.info("Building runtime") + subprocess.call(["python3", "-m", "artiq.gateware.targets.kc705", + "-H", "nist_clock", + "--no-compile-gateware", + "--output-dir", "/tmp/kc705"]) + + elif action == "boot": + logger.info("Uploading runtime") + get_sftp().mkdir("/tmp/{tmp}".format(tmp=tmp)) + get_sftp().put("/tmp/kc705/software/runtime/runtime.bin", + "/tmp/{tmp}/runtime.bin".format(tmp=tmp)) + + logger.info("Booting runtime") + flterm = run_command( + "{env} python3 flterm.py {serial} " + + "--kernel /tmp/{tmp}/runtime.bin --upload-only") + artiq_flash = run_command( + "{env} artiq_flash start") + drain(flterm) + + elif action == "connect": + def forwarder(port): + listener = socket.socket() + listener.bind(('localhost', port)) + listener.listen(1) + while True: + local_stream, peer_addr = listener.accept() + logger.info("Accepting %s:%s and opening SSH channel to %s:%s", + *peer_addr, args.ip, port) + remote_stream = get_ssh().get_transport() \ + .open_channel('direct-tcpip', (args.ip, port), peer_addr) + while True: + r, w, x = select.select([local_stream, remote_stream], [], []) + if local_stream in r: + data = local_stream.recv(1024) + if data == b"": + break + remote_stream.send(data) + if remote_stream in r: + data = remote_stream.recv(1024) + if data == b"": + break + local_stream.send(data) + + for port in (1381, 1382): + thread = threading.Thread(target=forwarder, args=(port,), + name="port-{}".format(port), daemon=True) + thread.start() + + logger.info("Connecting to device") + flterm = run_command( + "{env} python3 flterm.py {serial} --output-only") + drain(flterm) + + else: + logger.error("Unknown action {}".format(action)) + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index c3c50e8c1..693da9a21 100755 --- a/setup.py +++ b/setup.py @@ -18,6 +18,7 @@ requirements = [ "quamash", "pyqtgraph", "pygit2", "aiohttp", "llvmlite_artiq", "pythonparser", "python-Levenshtein", "lit", "OutputCheck", + "paramiko" ] console_scripts = [ @@ -27,6 +28,7 @@ console_scripts = [ "artiq_coreconfig=artiq.frontend.artiq_coreconfig:main", "artiq_corelog=artiq.frontend.artiq_corelog:main", "artiq_ctlmgr=artiq.frontend.artiq_ctlmgr:main", + "artiq_devtool=artiq.frontend.artiq_devtool:main", "artiq_influxdb=artiq.frontend.artiq_influxdb:main", "artiq_master=artiq.frontend.artiq_master:main", "artiq_mkfs=artiq.frontend.artiq_mkfs:main", From fbc24204434551acf125e6cbd2b96d8c0403e5ea Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 11 Nov 2016 11:05:37 +0800 Subject: [PATCH 15/47] setup: remove paramiko dependency (optional and developer-only) --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 693da9a21..00ecb3355 100755 --- a/setup.py +++ b/setup.py @@ -18,7 +18,6 @@ requirements = [ "quamash", "pyqtgraph", "pygit2", "aiohttp", "llvmlite_artiq", "pythonparser", "python-Levenshtein", "lit", "OutputCheck", - "paramiko" ] console_scripts = [ From 8b6418c604705c0c45b3138e8529267abbd2b819 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 10 Nov 2016 21:05:24 +0000 Subject: [PATCH 16/47] artiq_devtool: more robust port forwarding. --- artiq/frontend/artiq_devtool.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 4c6aba681..5eb844666 100644 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -105,6 +105,7 @@ def main(): elif action == "connect": def forwarder(port): listener = socket.socket() + listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) listener.bind(('localhost', port)) listener.listen(1) while True: @@ -114,17 +115,22 @@ def main(): remote_stream = get_ssh().get_transport() \ .open_channel('direct-tcpip', (args.ip, port), peer_addr) while True: - r, w, x = select.select([local_stream, remote_stream], [], []) - if local_stream in r: - data = local_stream.recv(1024) - if data == b"": - break - remote_stream.send(data) - if remote_stream in r: - data = remote_stream.recv(1024) - if data == b"": - break - local_stream.send(data) + try: + r, w, x = select.select([local_stream, remote_stream], [], []) + if local_stream in r: + data = local_stream.recv(1024) + if data == b"": + break + remote_stream.send(data) + if remote_stream in r: + data = remote_stream.recv(1024) + if data == b"": + break + local_stream.send(data) + except Exception as e: + logger.exception("Forward error on port %s", port) + local_stream.close() + remote_stream.close() for port in (1381, 1382): thread = threading.Thread(target=forwarder, args=(port,), From d3ee858d1670094080f7e27c56e683b081c3beef Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 12 Nov 2016 04:08:58 +0000 Subject: [PATCH 17/47] =?UTF-8?q?llvm=5Fir=5Fgenerator:=20use=20!{?= =?UTF-8?q?=E2=86=92unconditionally.}invariant.load=20metadata.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helps LICM, among other things. --- artiq/compiler/transforms/llvm_ir_generator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 1095c2e64..0a41479b8 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -651,7 +651,7 @@ class LLVMIRGenerator: 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('unconditionally.invariant.load', self.empty_metadata) llouterenv.set_metadata('nonnull', self.empty_metadata) return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name) @@ -795,7 +795,7 @@ class LLVMIRGenerator: 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) + llvalue.set_metadata('unconditionally.invariant.load', self.empty_metadata) if isinstance(llvalue.type, ll.PointerType): self.mark_dereferenceable(llvalue) return llvalue @@ -1050,7 +1050,7 @@ class LLVMIRGenerator: 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('unconditionally.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: From 5eb940deb7b0af34aeec1701ad8fbaa53d05c12b Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 12 Nov 2016 04:09:34 +0000 Subject: [PATCH 18/47] conda: bump llvmlite-artiq dep. --- conda/artiq/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 05ac59ceb..580a20397 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -18,7 +18,7 @@ requirements: - binutils-or1k-linux run: - python >=3.5.2 - - llvmlite-artiq 0.12.0.dev py35_27 + - llvmlite-artiq 0.12.0.dev py35_28 - lit - outputcheck - scipy From 7c2b1155ef6c49eb7ab378ad050ba0dd250834cd Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 12 Nov 2016 13:58:00 +0000 Subject: [PATCH 19/47] conda: bump llvmlite-artiq dep. --- conda/artiq/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 580a20397..0d85408bb 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -18,7 +18,7 @@ requirements: - binutils-or1k-linux run: - python >=3.5.2 - - llvmlite-artiq 0.12.0.dev py35_28 + - llvmlite-artiq 0.12.0.dev py35_29 - lit - outputcheck - scipy From dca3fb5c9658b7a977f7e1205e9d4747c4aa7e7a Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 12 Nov 2016 20:11:55 +0000 Subject: [PATCH 20/47] artiq_devtool: abort if build failed. --- artiq/frontend/artiq_devtool.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 5eb844666..7d4d71f5a 100644 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -83,10 +83,14 @@ def main(): for action in args.actions: if action == "build": logger.info("Building runtime") - subprocess.call(["python3", "-m", "artiq.gateware.targets.kc705", - "-H", "nist_clock", - "--no-compile-gateware", - "--output-dir", "/tmp/kc705"]) + try: + subprocess.check_call(["python3", "-m", "artiq.gateware.targets.kc705", + "-H", "nist_clock", + "--no-compile-gateware", + "--output-dir", "/tmp/kc705"]) + except subprocess.CalledProcessError: + logger.error("Build failed") + sys.exit(1) elif action == "boot": logger.info("Uploading runtime") From acc5e53b32597adc749fe990ff7eed713e0168be Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 12 Nov 2016 18:28:29 +0000 Subject: [PATCH 21/47] runtime: print microsecond timestamps in debug messages. --- artiq/runtime.rs/src/clock.rs | 7 +++++++ artiq/runtime.rs/src/logger.rs | 10 ++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/artiq/runtime.rs/src/clock.rs b/artiq/runtime.rs/src/clock.rs index 3c203a196..40e56eea9 100644 --- a/artiq/runtime.rs/src/clock.rs +++ b/artiq/runtime.rs/src/clock.rs @@ -12,6 +12,13 @@ pub fn init() { } } +pub fn get_us() -> u64 { + unsafe { + csr::timer0::update_value_write(1); + (INIT - csr::timer0::value_read()) / (FREQ / 1_000_000) + } +} + pub fn get_ms() -> u64 { unsafe { csr::timer0::update_value_write(1); diff --git a/artiq/runtime.rs/src/logger.rs b/artiq/runtime.rs/src/logger.rs index d09995bf7..e01248da2 100644 --- a/artiq/runtime.rs/src/logger.rs +++ b/artiq/runtime.rs/src/logger.rs @@ -2,6 +2,7 @@ use core::{mem, ptr}; use core::cell::RefCell; use log::{self, Log, LogMetadata, LogRecord, LogLevelFilter}; use log_buffer::LogBuffer; +use clock; pub struct BufferLogger { buffer: RefCell> @@ -57,10 +58,11 @@ impl Log for BufferLogger { fn log(&self, record: &LogRecord) { if self.enabled(record.metadata()) { use core::fmt::Write; - writeln!(self.buffer.borrow_mut(), "{:>5}({}): {}", - record.level(), record.target(), record.args()).unwrap(); - println!("{:>5}({}): {}", - record.level(), record.target(), record.args()); + writeln!(self.buffer.borrow_mut(), + "[{:12}us] {:>5}({}): {}", + clock::get_us(), record.level(), record.target(), record.args()).unwrap(); + println!("[{:12}us] {:>5}({}): {}", + clock::get_us(), record.level(), record.target(), record.args()); } } } From 3ce1826891e35a25aceb2fd766e44b446cf8a5a5 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 12 Nov 2016 20:16:25 +0000 Subject: [PATCH 22/47] runtime: don't print debug messages to the UART. It takes ~4ms to print an empty log line because of how slow the UART is. This makes the log timestamps useless for debugging performance problems. After this commit, it takes ~75us to print an empty log line instead, which pessimizes test_rpc_timing by less than 2ms with tracing enabled. --- artiq/runtime.rs/src/lib.rs | 2 +- artiq/runtime.rs/src/logger.rs | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/artiq/runtime.rs/src/lib.rs b/artiq/runtime.rs/src/lib.rs index 48efd5d0d..b3350dfc8 100644 --- a/artiq/runtime.rs/src/lib.rs +++ b/artiq/runtime.rs/src/lib.rs @@ -97,7 +97,7 @@ pub extern "C" fn _Unwind_Resume() -> ! { #[no_mangle] pub unsafe extern fn rust_main() { - static mut LOG_BUFFER: [u8; 4096] = [0; 4096]; + static mut LOG_BUFFER: [u8; 65536] = [0; 65536]; BufferLogger::new(&mut LOG_BUFFER[..]) .register(move || { info!("booting ARTIQ..."); diff --git a/artiq/runtime.rs/src/logger.rs b/artiq/runtime.rs/src/logger.rs index e01248da2..77d1d01d5 100644 --- a/artiq/runtime.rs/src/logger.rs +++ b/artiq/runtime.rs/src/logger.rs @@ -1,6 +1,6 @@ use core::{mem, ptr}; use core::cell::RefCell; -use log::{self, Log, LogMetadata, LogRecord, LogLevelFilter}; +use log::{self, Log, LogLevel, LogMetadata, LogRecord, LogLevelFilter}; use log_buffer::LogBuffer; use clock; @@ -61,8 +61,10 @@ impl Log for BufferLogger { writeln!(self.buffer.borrow_mut(), "[{:12}us] {:>5}({}): {}", clock::get_us(), record.level(), record.target(), record.args()).unwrap(); - println!("[{:12}us] {:>5}({}): {}", - clock::get_us(), record.level(), record.target(), record.args()); + if record.level() <= LogLevel::Info { + println!("[{:12}us] {:>5}({}): {}", + clock::get_us(), record.level(), record.target(), record.args()); + } } } } From feed91d8b2bb73b49ce89e52678d19e1988254c7 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 12 Nov 2016 23:06:33 +0000 Subject: [PATCH 23/47] runtime: buffer RPC send packets. This brings mean RPC time from ~45ms to ~2ms. The cause of the slowness without buffering is, primarily, that lwip is severely pessimized by small writes, whether with Nagle on or off. (In fact, disabling Nagle makes it function *better* on many small writes, which begs the question of what's the point of having Nagle there in the first place.) In practical terms, the slowness appears only when writing a 4-byte buffer (the synchronization segment); writing buffers of other sizes does not trigger the problem. This all is extremely confusing and the fix is partly palliative, but since it seems to work reliably and we're migrating off lwip I think it is unwise to spend any more time debugging this. --- artiq/runtime.rs/src/session.rs | 7 ++++--- artiq/test/coredevice/test_rtio.py | 8 +++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/artiq/runtime.rs/src/session.rs b/artiq/runtime.rs/src/session.rs index 8ad957a61..8589971a0 100644 --- a/artiq/runtime.rs/src/session.rs +++ b/artiq/runtime.rs/src/session.rs @@ -114,7 +114,7 @@ fn host_read(stream: &mut TcpStream) -> io::Result { Ok(request) } -fn host_write(stream: &mut TcpStream, reply: host::Reply) -> io::Result<()> { +fn host_write(stream: &mut Write, reply: host::Reply) -> io::Result<()> { trace!("comm->host {:?}", reply); reply.write_to(stream) } @@ -389,8 +389,9 @@ fn process_kern_message(waiter: Waiter, match stream { None => unexpected!("unexpected RPC in flash kernel"), Some(ref mut stream) => { - try!(host_write(stream, host::Reply::RpcRequest { async: async })); - try!(rpc::send_args(&mut BufWriter::new(stream), service, tag, data)); + let writer = &mut BufWriter::new(stream); + try!(host_write(writer, host::Reply::RpcRequest { async: async })); + try!(rpc::send_args(writer, service, tag, data)); if !async { session.kernel_state = KernelState::RpcWait } diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index f60abd643..061d5fc3c 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -450,6 +450,8 @@ class RPCTest(ExperimentCase): "timings are dependent on CPU load and network conditions") def test_rpc_timing(self): self.execute(RPCTiming) - self.assertGreater(self.dataset_mgr.get("rpc_time_mean"), 100*ns) - self.assertLess(self.dataset_mgr.get("rpc_time_mean"), 15*ms) - self.assertLess(self.dataset_mgr.get("rpc_time_stddev"), 2*ms) + rpc_time_mean = self.dataset_mgr.get("rpc_time_mean") + print(rpc_time_mean) + self.assertGreater(rpc_time_mean, 100*ns) + self.assertLess(rpc_time_mean, 2*ms) + self.assertLess(self.dataset_mgr.get("rpc_time_stddev"), 1*ms) From 18c394976ebd841c3ba31e5e72a92821a81e3cc0 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 13 Nov 2016 00:33:24 +0000 Subject: [PATCH 24/47] runtime: disable the Nagle algorithm entirely. See also commit feed91d; that commit fixed the test_rpc_timing test, but caused frequent hangs elsewhere, which were also caused by buggy Nagle implementation. Just disable this entirely, as with our explicit buffering it provides no benefit anyway. --- artiq/runtime.rs/liblwip-sys/lib.rs | 1 + artiq/runtime.rs/liblwip/lib.rs | 1 + artiq/runtime/main.c | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/artiq/runtime.rs/liblwip-sys/lib.rs b/artiq/runtime.rs/liblwip-sys/lib.rs index 82a7c5bcf..912b7c381 100644 --- a/artiq/runtime.rs/liblwip-sys/lib.rs +++ b/artiq/runtime.rs/liblwip-sys/lib.rs @@ -149,6 +149,7 @@ extern { // nonstandard pub fn tcp_sndbuf_(pcb: *mut tcp_pcb) -> u16; pub fn tcp_so_options_(pcb: *mut tcp_pcb) -> *mut u8; + pub fn tcp_nagle_disable_(pcb: *mut tcp_pcb); pub fn udp_new() -> *mut udp_pcb; pub fn udp_new_ip_type(type_: ip_addr_type) -> *mut udp_pcb; diff --git a/artiq/runtime.rs/liblwip/lib.rs b/artiq/runtime.rs/liblwip/lib.rs index f94b65dac..7eed9497b 100644 --- a/artiq/runtime.rs/liblwip/lib.rs +++ b/artiq/runtime.rs/liblwip/lib.rs @@ -549,6 +549,7 @@ impl TcpStream { lwip_sys::tcp_recv(raw, Some(recv)); lwip_sys::tcp_sent(raw, Some(sent)); lwip_sys::tcp_err(raw, Some(err)); + lwip_sys::tcp_nagle_disable_(raw); TcpStream { raw: raw, state: state } } } diff --git a/artiq/runtime/main.c b/artiq/runtime/main.c index d5db5e5dc..c9f6f0951 100644 --- a/artiq/runtime/main.c +++ b/artiq/runtime/main.c @@ -177,6 +177,10 @@ u8_t* tcp_so_options_(struct tcp_pcb *pcb) { return &pcb->so_options; } +void tcp_nagle_disable_(struct tcp_pcb *pcb) { + tcp_nagle_disable(pcb); +} + int main(void) { irq_setmask(0); From c7844d5223c7e377e65401c344d97984a2ea8d10 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 17 Nov 2016 15:20:21 +0000 Subject: [PATCH 25/47] runtime: use proper format for git commit. Fixes #620. --- artiq/runtime.rs/build.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/runtime.rs/build.rs b/artiq/runtime.rs/build.rs index e545ea3d4..39403d146 100644 --- a/artiq/runtime.rs/build.rs +++ b/artiq/runtime.rs/build.rs @@ -13,8 +13,10 @@ fn main() { let dest_path = Path::new(&out_dir).join("git_info.rs"); let mut f = File::create(&dest_path).unwrap(); - writeln!(f, "const GIT_COMMIT: &'static str = {:?};", - git_describe().unwrap()).unwrap(); + let id = git_describe().unwrap(); + let id = id.split("-").collect::>(); + let id = format!("{}+{}.{}", id[0], id[1], id[2]); + writeln!(f, "const GIT_COMMIT: &'static str = {:?};", id).unwrap(); println!("cargo:rerun-if-changed=../../.git/HEAD"); for entry in WalkDir::new("../../.git/refs") { From 2015fe9de061d3a7f912e13be7caf337d1d245ea Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 18 Nov 2016 10:35:36 +0000 Subject: [PATCH 26/47] doc: update installing_from_source for LLVM 3.9 transitionl --- doc/manual/installing_from_source.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/installing_from_source.rst b/doc/manual/installing_from_source.rst index 32d1e3481..c25e74bdf 100644 --- a/doc/manual/installing_from_source.rst +++ b/doc/manual/installing_from_source.rst @@ -48,9 +48,9 @@ and the ARTIQ kernels. * Install LLVM and Clang: :: $ cd ~/artiq-dev - $ git clone -b artiq-3.8 https://github.com/m-labs/llvm-or1k + $ git clone -b artiq-3.9 https://github.com/m-labs/llvm-or1k $ cd llvm-or1k - $ git clone -b artiq-3.8 https://github.com/m-labs/clang-or1k tools/clang + $ git clone -b artiq-3.9 https://github.com/m-labs/clang-or1k tools/clang $ mkdir build $ cd build From 4a62e09bd4f6a1a692d770990dbd93ac80111057 Mon Sep 17 00:00:00 2001 From: David Leibrandt Date: Sun, 20 Nov 2016 15:17:38 +0800 Subject: [PATCH 27/47] gateware: increase RTIO FIFO sizes for NIST_CLOCK. Closes #623 --- artiq/gateware/targets/kc705.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 486f047f0..c4ab7c3d7 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -230,16 +230,16 @@ class NIST_CLOCK(_NIST_Ions): if i % 4 == 3: phy = ttl_serdes_7series.Inout_8X(platform.request("ttl", i)) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=1024)) else: phy = ttl_serdes_7series.Output_8X(platform.request("ttl", i)) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=1024)) for i in range(2): phy = ttl_serdes_7series.Inout_8X(platform.request("pmt", i)) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16384)) phy = ttl_serdes_7series.Inout_8X(platform.request("user_sma_gpio_n_33")) self.submodules += phy @@ -279,7 +279,7 @@ class NIST_CLOCK(_NIST_Ions): phy = dds.AD9914(platform.request("dds"), 11, onehot=True) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, - ofifo_depth=512, + ofifo_depth=16384, ififo_depth=4)) self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) From d7f439792437cdb22c057c897ff4f0450b70b2ab Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 20 Nov 2016 09:47:43 +0000 Subject: [PATCH 28/47] coredevice.dds: update from obsolete int(width=) syntax (fixes #621). --- artiq/coredevice/dds.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/dds.py b/artiq/coredevice/dds.py index ffec5d710..63a147742 100644 --- a/artiq/coredevice/dds.py +++ b/artiq/coredevice/dds.py @@ -1,6 +1,7 @@ from artiq.language.core import * from artiq.language.types import * from artiq.language.units import * +from numpy import int64 _PHASE_MODE_DEFAULT = -1 @@ -111,14 +112,14 @@ class _DDSGeneric: """Returns the frequency tuning word corresponding to the given frequency. """ - return round(int(2, width=64)**32*frequency/self.core_dds.sysclk) + return round(int64(2)**32*frequency/self.core_dds.sysclk) @portable(flags=["fast-math"]) def ftw_to_frequency(self, ftw): """Returns the frequency corresponding to the given frequency tuning word. """ - return ftw*self.core_dds.sysclk/int(2, width=64)**32 + return ftw*self.core_dds.sysclk/int64(2)**32 @portable(flags=["fast-math"]) def turns_to_pow(self, turns): From abf2b32b2001f19884d1a3a9b6b8cc2e4010c0fb Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 20 Nov 2016 09:48:49 +0000 Subject: [PATCH 29/47] coredevice.dds: work around the round(numpy.float64()) snafu. --- artiq/coredevice/dds.py | 6 +++--- doc/manual/compiler.rst | 31 +++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/dds.py b/artiq/coredevice/dds.py index 63a147742..1437ff2df 100644 --- a/artiq/coredevice/dds.py +++ b/artiq/coredevice/dds.py @@ -112,7 +112,7 @@ class _DDSGeneric: """Returns the frequency tuning word corresponding to the given frequency. """ - return round(int64(2)**32*frequency/self.core_dds.sysclk) + return round(float(int64(2)**32*frequency/self.core_dds.sysclk)) @portable(flags=["fast-math"]) def ftw_to_frequency(self, ftw): @@ -125,7 +125,7 @@ class _DDSGeneric: def turns_to_pow(self, turns): """Returns the phase offset word corresponding to the given phase in turns.""" - return round(turns*2**self.pow_width) + return round(float(turns*2**self.pow_width)) @portable(flags=["fast-math"]) def pow_to_turns(self, pow): @@ -136,7 +136,7 @@ class _DDSGeneric: @portable(flags=["fast-math"]) def amplitude_to_asf(self, amplitude): """Returns amplitude scale factor corresponding to given amplitude.""" - return round(amplitude*0x0fff) + return round(float(amplitude*0x0fff)) @portable(flags=["fast-math"]) def asf_to_amplitude(self, asf): diff --git a/doc/manual/compiler.rst b/doc/manual/compiler.rst index 02c56e516..ef26aef8c 100644 --- a/doc/manual/compiler.rst +++ b/doc/manual/compiler.rst @@ -10,7 +10,7 @@ A number of Python features can be used inside a kernel for compilation and exec * Booleans * 32-bit signed integers (default size) -* 64-bit signed integers (use ``int(n, width=64)`` to convert) +* 64-bit signed integers (use ``numpy.int64`` to convert) * Double-precision floating point numbers * Lists of any supported types * User-defined classes, with attributes of any supported types (attributes that are not used anywhere in the kernel are ignored) @@ -36,7 +36,7 @@ The Python types correspond to ARTIQ type annotations as follows: +-------------+-------------------------+ | bool | TBool | +-------------+-------------------------+ -| int | TInt32, TInt64 | +| int | TInt32 or TInt64 | +-------------+-------------------------+ | float | TFloat | +-------------+-------------------------+ @@ -46,6 +46,33 @@ The Python types correspond to ARTIQ type annotations as follows: +-------------+-------------------------+ | range | TRange32, TRange64 | +-------------+-------------------------+ +| numpy.int32 | TInt32 | ++-------------+-------------------------+ +| numpy.int64 | TInt64 | ++-------------+-------------------------+ +| numpy.float64 | TFloat | ++-------------+-------------------------+ + +Pitfalls +-------- + +The ARTIQ compiler accepts *nearly* a strict subset of Python 3. However, by necessity there +is a number of differences that can lead to bugs. + +Arbitrary-length integers are not supported at all on the core device; all integers are +either 32-bit or 64-bit. This especially affects calculations that result in a 32-bit signed +overflow; if the compiler detects a constant that doesn't fit into 32 bits, the entire expression +will be upgraded to 64-bit arithmetics, however if all constants are small, 32-bit arithmetics +will be used even if the result will overflow. Overflows are not detected. + +The result of calling the builtin ``round`` function is different when used with +the builtin ``float`` type and the ``numpy.float64`` type on the host interpreter; ``round(1.0)`` +returns an integer value 1, whereas ``round(numpy.float64(1.0))`` returns a floating point value +``numpy.float64(1.0)``. Since both ``float`` and ``numpy.float64`` are mapped to +the builtin ``float`` type on the core device, this can lead to problems in functions marked +``@portable``; the workaround is to explicitly cast the argument of ``round`` to ``float``: +``round(float(numpy.float64(1.0)))`` returns an integer on the core device as well as on the host +interpreter. Asynchronous RPCs ----------------- From 30598720f4af5d7a7b85c69c87dcafafc64e9aef Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 20 Nov 2016 09:49:06 +0000 Subject: [PATCH 30/47] Fix whitespace. --- artiq/gateware/targets/kc705.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index c4ab7c3d7..b79b31545 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -81,7 +81,7 @@ class _RTIOCRG(Module, AutoCSR): # The default user SMA voltage on KC705 is 2.5V, and the Migen platform # follows this default. But since the SMAs are on the same bank as the DDS, # which is set to 3.3V by reprogramming the KC705 power ICs, we need to -# redefine them here. +# redefine them here. _sma33_io = [ ("user_sma_gpio_p_33", 0, Pins("Y23"), IOStandard("LVCMOS33")), ("user_sma_gpio_n_33", 0, Pins("Y24"), IOStandard("LVCMOS33")), @@ -293,7 +293,7 @@ class NIST_CLOCK(_NIST_Ions): class NIST_QC2(_NIST_Ions): """ NIST QC2 hardware, as used in Quantum I and Quantum II, with new backplane - and 24 DDS channels. Two backplanes are used. + and 24 DDS channels. Two backplanes are used. """ def __init__(self, cpu_type="or1k", **kwargs): _NIST_Ions.__init__(self, cpu_type, **kwargs) @@ -310,19 +310,19 @@ class NIST_QC2(_NIST_Ions): platform.request("ttl", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) - + # CLK0, CLK1 are for clock generators, on backplane SMP connectors - for i in range(2): + for i in range(2): phy = ttl_simple.ClockGen( platform.request("clkout", i)) self.submodules += phy - clock_generators.append(rtio.Channel.from_phy(phy)) + clock_generators.append(rtio.Channel.from_phy(phy)) # user SMA on KC705 board phy = ttl_serdes_7series.Inout_8X(platform.request("user_sma_gpio_n_33")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) - + phy = ttl_simple.Output(platform.request("user_led", 2)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From f5cca6b09ec35e7ac9cd606adf3fd335d120f111 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 20 Nov 2016 12:48:26 +0000 Subject: [PATCH 31/47] analyses.invariant_detection: implement (#622). --- artiq/compiler/analyses/__init__.py | 1 + .../compiler/analyses/invariant_detection.py | 49 +++++++++++++++++++ artiq/compiler/module.py | 5 +- .../compiler/transforms/llvm_ir_generator.py | 6 ++- 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 artiq/compiler/analyses/invariant_detection.py diff --git a/artiq/compiler/analyses/__init__.py b/artiq/compiler/analyses/__init__.py index f1553fc74..21da39d23 100644 --- a/artiq/compiler/analyses/__init__.py +++ b/artiq/compiler/analyses/__init__.py @@ -1,3 +1,4 @@ from .constness import Constness from .domination import DominatorTree from .devirtualization import Devirtualization +from .invariant_detection import InvariantDetection diff --git a/artiq/compiler/analyses/invariant_detection.py b/artiq/compiler/analyses/invariant_detection.py new file mode 100644 index 000000000..665c7317b --- /dev/null +++ b/artiq/compiler/analyses/invariant_detection.py @@ -0,0 +1,49 @@ +""" +: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/module.py b/artiq/compiler/module.py index e169a656e..d1d2b1efc 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -40,7 +40,7 @@ class Source: return cls(source.Buffer(f.read(), filename, 1), engine=engine) class Module: - def __init__(self, src, ref_period=1e-6, attribute_writeback=True): + def __init__(self, src, ref_period=1e-6, attribute_writeback=True, remarks=True): self.attribute_writeback = attribute_writeback self.engine = src.engine self.embedding_map = src.embedding_map @@ -61,6 +61,7 @@ class Module: local_access_validator = validators.LocalAccessValidator(engine=self.engine) devirtualization = analyses.Devirtualization() interleaver = transforms.Interleaver(engine=self.engine) + invariant_detection = analyses.InvariantDetection(engine=self.engine) int_monomorphizer.visit(src.typedtree) inferencer.visit(src.typedtree) @@ -74,6 +75,8 @@ class Module: dead_code_eliminator.process(self.artiq_ir) interleaver.process(self.artiq_ir) local_access_validator.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.""" diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 0a41479b8..d1dac2810 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1151,8 +1151,12 @@ class LLVMIRGenerator: 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: + + flags = insn.target_function().type.flags + if 'nounwind' in flags: llfun.attributes.add('nounwind') + if 'nowrite' in flags: + llfun.attributes.add('inaccessiblememonly') return llfun, list(llargs) From ad1049d59a308cb8ef8ddbee6e88a8704657fa71 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 20 Nov 2016 21:35:07 +0800 Subject: [PATCH 32/47] Revert "gateware: increase RTIO FIFO sizes for NIST_CLOCK. Closes #623" This reverts commit 4a62e09bd4f6a1a692d770990dbd93ac80111057. --- artiq/gateware/targets/kc705.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index b79b31545..b6b04461b 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -230,16 +230,16 @@ class NIST_CLOCK(_NIST_Ions): if i % 4 == 3: phy = ttl_serdes_7series.Inout_8X(platform.request("ttl", i)) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=1024)) + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) else: phy = ttl_serdes_7series.Output_8X(platform.request("ttl", i)) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=1024)) + rtio_channels.append(rtio.Channel.from_phy(phy)) for i in range(2): phy = ttl_serdes_7series.Inout_8X(platform.request("pmt", i)) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16384)) + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) phy = ttl_serdes_7series.Inout_8X(platform.request("user_sma_gpio_n_33")) self.submodules += phy @@ -279,7 +279,7 @@ class NIST_CLOCK(_NIST_Ions): phy = dds.AD9914(platform.request("dds"), 11, onehot=True) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, - ofifo_depth=16384, + ofifo_depth=512, ififo_depth=4)) self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) From cdb29f9caae6297c3950ed1ea039045a1a43ec60 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 20 Nov 2016 14:32:16 +0000 Subject: [PATCH 33/47] Revert accidentally committed code. --- artiq/compiler/transforms/llvm_ir_generator.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index d1dac2810..0a41479b8 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1151,12 +1151,8 @@ class LLVMIRGenerator: byvals = [i + 1 for i in byvals] for i in byvals: llfun.args[i].add_attribute('byval') - - flags = insn.target_function().type.flags - if 'nounwind' in flags: + if 'nounwind' in insn.target_function().type.flags: llfun.attributes.add('nounwind') - if 'nowrite' in flags: - llfun.attributes.add('inaccessiblememonly') return llfun, list(llargs) From eb184668206b9d781b5b3708329103a7c90cc0da Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 20 Nov 2016 22:56:48 +0800 Subject: [PATCH 34/47] conda: use development version of migen/misoc --- conda/artiq-kc705-nist_clock/meta.yaml | 4 ++-- conda/artiq-kc705-nist_qc1/meta.yaml | 4 ++-- conda/artiq-kc705-nist_qc2/meta.yaml | 4 ++-- conda/artiq-pipistrello-nist_qc1/meta.yaml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/conda/artiq-kc705-nist_clock/meta.yaml b/conda/artiq-kc705-nist_clock/meta.yaml index 853a5cfae..bc56bf200 100644 --- a/conda/artiq-kc705-nist_clock/meta.yaml +++ b/conda/artiq-kc705-nist_clock/meta.yaml @@ -12,8 +12,8 @@ build: requirements: build: - - migen 0.4 - - misoc 0.4 + - migen 0.5.dev + - misoc 0.5.dev - llvm-or1k - binutils-or1k-linux >=2.27 - rust-core-or1k diff --git a/conda/artiq-kc705-nist_qc1/meta.yaml b/conda/artiq-kc705-nist_qc1/meta.yaml index d5be16c2e..2ee0b5b54 100644 --- a/conda/artiq-kc705-nist_qc1/meta.yaml +++ b/conda/artiq-kc705-nist_qc1/meta.yaml @@ -12,8 +12,8 @@ build: requirements: build: - - migen 0.4 - - misoc 0.4 + - migen 0.5.dev + - misoc 0.5.dev - llvm-or1k - binutils-or1k-linux >=2.27 - rust-core-or1k diff --git a/conda/artiq-kc705-nist_qc2/meta.yaml b/conda/artiq-kc705-nist_qc2/meta.yaml index 54e5d2579..9a0223a9b 100644 --- a/conda/artiq-kc705-nist_qc2/meta.yaml +++ b/conda/artiq-kc705-nist_qc2/meta.yaml @@ -12,8 +12,8 @@ build: requirements: build: - - migen 0.4 - - misoc 0.4 + - migen 0.5.dev + - misoc 0.5.dev - llvm-or1k - binutils-or1k-linux >=2.27 - rust-core-or1k diff --git a/conda/artiq-pipistrello-nist_qc1/meta.yaml b/conda/artiq-pipistrello-nist_qc1/meta.yaml index a69497fff..06b1bc006 100644 --- a/conda/artiq-pipistrello-nist_qc1/meta.yaml +++ b/conda/artiq-pipistrello-nist_qc1/meta.yaml @@ -12,8 +12,8 @@ build: requirements: build: - - migen 0.4 - - misoc 0.4 + - migen 0.5.dev + - misoc 0.5.dev - llvm-or1k - binutils-or1k-linux >=2.27 - rust-core-or1k From 7af41bd29ce966dea8d97ae3118699e6e6143611 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 02:25:27 +0000 Subject: [PATCH 35/47] llvm_ir_generator: handle no-op coercions. --- artiq/compiler/transforms/llvm_ir_generator.py | 2 ++ artiq/test/lit/codegen/noop_coercion.py | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 artiq/test/lit/codegen/noop_coercion.py diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 0a41479b8..09e62aab8 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -848,6 +848,8 @@ class LLVMIRGenerator: 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) diff --git a/artiq/test/lit/codegen/noop_coercion.py b/artiq/test/lit/codegen/noop_coercion.py new file mode 100644 index 000000000..df4ce830b --- /dev/null +++ b/artiq/test/lit/codegen/noop_coercion.py @@ -0,0 +1,4 @@ +# RUN: %python -m artiq.compiler.testbench.llvmgen %s + +def f(): + return float(1.0) From b562b0fbc4b0169871db7f13516541e225a96735 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 03:10:41 +0000 Subject: [PATCH 36/47] artiq_devtool: detect a race condition during connect. --- artiq/frontend/artiq_devtool.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 7d4d71f5a..fc6f58048 100644 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -116,6 +116,10 @@ def main(): local_stream, peer_addr = listener.accept() logger.info("Accepting %s:%s and opening SSH channel to %s:%s", *peer_addr, args.ip, port) + if get_ssh().get_transport() is None: + logger.error("Trying to open a channel before the transport is ready!") + continue + remote_stream = get_ssh().get_transport() \ .open_channel('direct-tcpip', (args.ip, port), peer_addr) while True: From 06ea76336d84b6db1da4d314544d2d0d3980b73d Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 04:27:16 +0000 Subject: [PATCH 37/47] artiq_devtool: don't crash on invalid utf-8. --- artiq/frontend/artiq_devtool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index fc6f58048..b942b21f5 100644 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -78,7 +78,7 @@ def main(): char = chan.read(1) if char == b"": break - sys.stderr.write(char.decode("utf-8")) + sys.stderr.write(char.decode("utf-8", errors='replace')) for action in args.actions: if action == "build": From 009d3967409fb69e609e2e22f53b7c9d8224cb31 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 04:27:48 +0000 Subject: [PATCH 38/47] Move mu_to_seconds, seconds_to_mu to Core. --- artiq/compiler/builtins.py | 6 ----- artiq/compiler/prelude.py | 2 -- .../compiler/transforms/artiq_ir_generator.py | 14 ---------- artiq/compiler/transforms/inferencer.py | 6 ----- artiq/coredevice/ad5360.py | 7 +++-- artiq/coredevice/core.py | 18 +++++++++++++ artiq/coredevice/spi.py | 8 +++--- artiq/devices/pdq2/mediator.py | 6 ++--- artiq/examples/master/idle_kernel.py | 4 +-- .../repository/coredevice_examples/tdr.py | 2 +- artiq/language/core.py | 26 ------------------- artiq/sim/devices.py | 7 +++++ artiq/test/coredevice/test_portability.py | 2 +- artiq/test/coredevice/test_rtio.py | 16 ++++++------ artiq/test/lit/time/conversion.py | 5 ---- doc/manual/compiler.rst | 2 +- doc/manual/rtio.rst | 2 +- 17 files changed, 48 insertions(+), 85 deletions(-) delete mode 100644 artiq/test/lit/time/conversion.py diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index ee7306e3c..6ab7ffe15 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -203,12 +203,6 @@ def fn_delay_mu(): def fn_at_mu(): return types.TBuiltinFunction("at_mu") -def fn_mu_to_seconds(): - return types.TBuiltinFunction("mu_to_seconds") - -def fn_seconds_to_mu(): - return types.TBuiltinFunction("seconds_to_mu") - def fn_rtio_log(): return types.TBuiltinFunction("rtio_log") diff --git a/artiq/compiler/prelude.py b/artiq/compiler/prelude.py index e19ef6706..b0b8db762 100644 --- a/artiq/compiler/prelude.py +++ b/artiq/compiler/prelude.py @@ -44,8 +44,6 @@ def globals(): "now_mu": builtins.fn_now_mu(), "delay_mu": builtins.fn_delay_mu(), "at_mu": builtins.fn_at_mu(), - "mu_to_seconds": builtins.fn_mu_to_seconds(), - "seconds_to_mu": builtins.fn_seconds_to_mu(), # ARTIQ utility functions "rtio_log": builtins.fn_rtio_log(), diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 4575c381c..6ccd74f43 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1731,20 +1731,6 @@ class ARTIQIRGenerator(algorithm.Visitor): 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_builtin(typ, "mu_to_seconds"): - if len(node.args) == 1 and len(node.keywords) == 0: - arg = self.visit(node.args[0]) - arg_float = self.append(ir.Coerce(arg, builtins.TFloat())) - return self.append(ir.Arith(ast.Mult(loc=None), arg_float, self.ref_period)) - else: - assert False - elif types.is_builtin(typ, "seconds_to_mu"): - if len(node.args) == 1 and len(node.keywords) == 0: - arg = self.visit(node.args[0]) - arg_mu = self.append(ir.Arith(ast.Div(loc=None), arg, self.ref_period)) - return self.append(ir.Coerce(arg_mu, builtins.TInt64())) - else: - assert False 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): diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 920343b44..716f8041b 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -899,12 +899,6 @@ class Inferencer(algorithm.Visitor): elif types.is_builtin(typ, "at_mu"): simple_form("at_mu(time_mu:numpy.int64) -> None", [builtins.TInt64()]) - elif types.is_builtin(typ, "mu_to_seconds"): - simple_form("mu_to_seconds(time_mu:numpy.int64) -> float", - [builtins.TInt64()], builtins.TFloat()) - elif types.is_builtin(typ, "seconds_to_mu"): - simple_form("seconds_to_mu(time:float) -> numpy.int64", - [builtins.TFloat()], builtins.TInt64()) elif types.is_builtin(typ, "watchdog"): simple_form("watchdog(time:float) -> [builtin context manager]", [builtins.TFloat()], builtins.TNone()) diff --git a/artiq/coredevice/ad5360.py b/artiq/coredevice/ad5360.py index b2dbe79c6..3338db4ab 100644 --- a/artiq/coredevice/ad5360.py +++ b/artiq/coredevice/ad5360.py @@ -1,5 +1,4 @@ -from artiq.language.core import (kernel, portable, delay_mu, delay, - seconds_to_mu) +from artiq.language.core import (kernel, portable, delay_mu, delay) from artiq.language.units import ns, us from artiq.coredevice import spi @@ -166,10 +165,10 @@ class AD5360: self.bus.write_period_mu + self.bus.ref_period_mu) - 3*self.bus.ref_period_mu - - seconds_to_mu(1.5*us)) + self.core.seconds_to_mu(1.5*us)) for i in range(len(values)): self.write_channel(i, values[i], op) delay_mu(3*self.bus.ref_period_mu + # latency alignment ttl to spi - seconds_to_mu(1.5*us)) # t10 max busy low for one channel + self.core.seconds_to_mu(1.5*us)) # t10 max busy low for one channel self.load() delay_mu(-2*self.bus.ref_period_mu) # load(), t13 diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 58c2ca7a9..fceb576bc 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -1,4 +1,5 @@ import os, sys +import numpy from pythonparser import diagnostic @@ -124,6 +125,23 @@ class Core: return result + @portable + def seconds_to_mu(self, seconds): + """Converts seconds to the corresponding number of machine units + (RTIO cycles). + + :param seconds: time (in seconds) to convert. + """ + return numpy.int64(seconds//self.ref_period) + + @portable + def mu_to_seconds(self, mu): + """Converts machine units (RTIO cycles) to seconds. + + :param mu: cycle count to convert. + """ + return mu*self.ref_period + @kernel def get_rtio_counter_mu(self): return rtio_get_counter() diff --git a/artiq/coredevice/spi.py b/artiq/coredevice/spi.py index e2c551ff5..65943533f 100644 --- a/artiq/coredevice/spi.py +++ b/artiq/coredevice/spi.py @@ -1,7 +1,6 @@ import numpy -from artiq.language.core import (kernel, portable, seconds_to_mu, now_mu, - delay_mu, mu_to_seconds) +from artiq.language.core import (kernel, portable, now_mu, delay_mu) from artiq.language.units import MHz from artiq.coredevice.rtio import rtio_output, rtio_input_data @@ -59,8 +58,7 @@ class SPIMaster: """ def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) - self.ref_period_mu = seconds_to_mu(self.core.coarse_ref_period, - self.core) + self.ref_period_mu = self.core.seconds_to_mu(self.core.coarse_ref_period) self.channel = channel self.write_period_mu = numpy.int64(0) self.read_period_mu = numpy.int64(0) @@ -68,7 +66,7 @@ class SPIMaster: @portable def frequency_to_div(self, f): - return int(1/(f*mu_to_seconds(self.ref_period_mu))) + 1 + return int(1/(f*self.core.mu_to_seconds(self.ref_period_mu))) + 1 @kernel def set_config(self, flags=0, write_freq=20*MHz, read_freq=20*MHz): diff --git a/artiq/devices/pdq2/mediator.py b/artiq/devices/pdq2/mediator.py index 33fe24314..4b4adb5a6 100644 --- a/artiq/devices/pdq2/mediator.py +++ b/artiq/devices/pdq2/mediator.py @@ -94,7 +94,7 @@ class _Frame: def _arm(self): self.segment_delays = [ - seconds_to_mu(s.duration*delay_margin_factor, self.core) + self.core.seconds_to_mu(s.duration*delay_margin_factor) for s in self.segments] def _invalidate(self): @@ -125,7 +125,7 @@ class _Frame: raise ArmError() call_t = now_mu() - trigger_start_t = call_t - seconds_to_mu(trigger_duration/2) + trigger_start_t = call_t - self.core.seconds_to_mu(trigger_duration/2) if self.pdq.current_frame >= 0: # PDQ is in the middle of a frame. Check it is us. @@ -136,7 +136,7 @@ class _Frame: # to play our first segment. self.pdq.current_frame = self.frame_number self.pdq.next_segment = 0 - at_mu(trigger_start_t - seconds_to_mu(frame_setup)) + at_mu(trigger_start_t - self.core.seconds_to_mu(frame_setup)) self.pdq.frame0.set_o(bool(self.frame_number & 1)) self.pdq.frame1.set_o(bool((self.frame_number & 2) >> 1)) self.pdq.frame2.set_o(bool((self.frame_number & 4) >> 2)) diff --git a/artiq/examples/master/idle_kernel.py b/artiq/examples/master/idle_kernel.py index a1d27a36c..d4d746fd3 100644 --- a/artiq/examples/master/idle_kernel.py +++ b/artiq/examples/master/idle_kernel.py @@ -5,10 +5,10 @@ class IdleKernel(EnvExperiment): def build(self): self.setattr_device("core") self.setattr_device("led") - + @kernel def run(self): - start_time = now_mu() + 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() diff --git a/artiq/examples/master/repository/coredevice_examples/tdr.py b/artiq/examples/master/repository/coredevice_examples/tdr.py index 6ec7c0e09..a32015a7b 100644 --- a/artiq/examples/master/repository/coredevice_examples/tdr.py +++ b/artiq/examples/master/repository/coredevice_examples/tdr.py @@ -42,7 +42,7 @@ class TDR(EnvExperiment): pulse = 1e-6 # pulse length, larger than rtt self.t = [0 for i in range(2)] try: - self.many(n, seconds_to_mu(pulse, self.core)) + self.many(n, self.core.seconds_to_mu(pulse)) except PulseNotReceivedError: print("to few edges: cable too long or wiring bad") else: diff --git a/artiq/language/core.py b/artiq/language/core.py index c1c19c802..47c1746f3 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -15,7 +15,6 @@ __all__ = ["kernel", "portable", "rpc", "syscall", "host_only", kernel_globals = ( "sequential", "parallel", "interleave", "delay_mu", "now_mu", "at_mu", "delay", - "seconds_to_mu", "mu_to_seconds", "watchdog" ) __all__.extend(kernel_globals) @@ -213,31 +212,6 @@ def delay(duration): _time_manager.take_time(duration) -def seconds_to_mu(seconds, core=None): - """Converts seconds to the corresponding number of machine units - (RTIO cycles). - - :param seconds: time (in seconds) to convert. - :param core: core device for which to perform the conversion. Specify only - when running in the interpreter (not in kernel). - """ - if core is None: - raise ValueError("Core device must be specified for time conversion") - return numpy.int64(seconds//core.ref_period) - - -def mu_to_seconds(mu, core=None): - """Converts machine units (RTIO cycles) to seconds. - - :param mu: cycle count to convert. - :param core: core device for which to perform the conversion. Specify only - when running in the interpreter (not in kernel). - """ - if core is None: - raise ValueError("Core device must be specified for time conversion") - return mu*core.ref_period - - class _DummyWatchdog: def __init__(self, timeout): pass diff --git a/artiq/sim/devices.py b/artiq/sim/devices.py index 95e72f984..ff8e5eb57 100644 --- a/artiq/sim/devices.py +++ b/artiq/sim/devices.py @@ -1,4 +1,5 @@ from random import Random +import numpy from artiq.language.core import delay, at_mu, kernel from artiq.sim import time @@ -18,6 +19,12 @@ class Core: time.manager.timeline.clear() return r + def seconds_to_mu(self, seconds): + return numpy.int64(seconds//self.ref_period) + + def mu_to_seconds(self, mu): + return mu*self.ref_period + class Input: def __init__(self, dmgr, name): diff --git a/artiq/test/coredevice/test_portability.py b/artiq/test/coredevice/test_portability.py index d67aaa287..cd301d29b 100644 --- a/artiq/test/coredevice/test_portability.py +++ b/artiq/test/coredevice/test_portability.py @@ -83,7 +83,7 @@ class _PulseLogger(EnvExperiment): if not hasattr(self.parent_test, "first_timestamp"): self.parent_test.first_timestamp = t origin = self.parent_test.first_timestamp - t_usec = round(mu_to_seconds(t-origin, self.core)*1000000) + 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): diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 061d5fc3c..c55e44c1f 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -38,7 +38,7 @@ class RTT(EnvExperiment): t1 = self.ttl_inout.timestamp_mu() if t1 < 0: raise PulseNotReceived() - self.set_dataset("rtt", mu_to_seconds(t1 - t0)) + self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0)) class Loopback(EnvExperiment): @@ -62,7 +62,7 @@ class Loopback(EnvExperiment): t1 = self.loop_in.timestamp_mu() if t1 < 0: raise PulseNotReceived() - self.set_dataset("rtt", mu_to_seconds(t1 - t0)) + self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0)) class ClockGeneratorLoopback(EnvExperiment): @@ -93,7 +93,7 @@ class PulseRate(EnvExperiment): @kernel def run(self): self.core.reset() - dt = seconds_to_mu(300*ns) + dt = self.core.seconds_to_mu(300*ns) while True: for i in range(10000): try: @@ -104,7 +104,7 @@ class PulseRate(EnvExperiment): self.core.break_realtime() break else: - self.set_dataset("pulse_rate", mu_to_seconds(dt)) + self.set_dataset("pulse_rate", self.core.mu_to_seconds(dt)) return @@ -118,7 +118,7 @@ class PulseRateDDS(EnvExperiment): @kernel def run(self): self.core.reset() - dt = seconds_to_mu(5*us) + dt = self.core.seconds_to_mu(5*us) while True: delay(10*ms) for i in range(1250): @@ -132,7 +132,7 @@ class PulseRateDDS(EnvExperiment): self.core.break_realtime() break else: - self.set_dataset("pulse_rate", mu_to_seconds(dt//2)) + self.set_dataset("pulse_rate", self.core.mu_to_seconds(dt//2)) return @@ -403,7 +403,7 @@ class CoredeviceTest(ExperimentCase): self.execute(TimeKeepsRunning) t2 = self.dataset_mgr.get("time_at_start") - dead_time = mu_to_seconds(t2 - t1, self.device_mgr.get("core")) + dead_time = self.core.mu_to_seconds(t2 - t1, self.device_mgr.get("core")) print(dead_time) self.assertGreater(dead_time, 1*ms) self.assertLess(dead_time, 2500*ms) @@ -434,7 +434,7 @@ class RPCTiming(EnvExperiment): t1 = self.core.get_rtio_counter_mu() self.nop() t2 = self.core.get_rtio_counter_mu() - self.ts[i] = mu_to_seconds(t2 - t1) + self.ts[i] = self.core.mu_to_seconds(t2 - t1) def run(self): self.ts = [0. for _ in range(self.repeats)] diff --git a/artiq/test/lit/time/conversion.py b/artiq/test/lit/time/conversion.py deleted file mode 100644 index 6a89034d6..000000000 --- a/artiq/test/lit/time/conversion.py +++ /dev/null @@ -1,5 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s -# REQUIRES: time - -assert seconds_to_mu(2.0) == 2000000 -assert mu_to_seconds(1500000) == 1.5 diff --git a/doc/manual/compiler.rst b/doc/manual/compiler.rst index ef26aef8c..95bdd286a 100644 --- a/doc/manual/compiler.rst +++ b/doc/manual/compiler.rst @@ -151,7 +151,7 @@ In the synthetic example above, the compiler will be able to detect that the res @kernel def loop(self): - precomputed_delay_mu = seconds_to_mu(self.worker.interval / 5.0) + precomputed_delay_mu = self.core.seconds_to_mu(self.worker.interval / 5.0) for _ in range(100): delay_mu(precomputed_delay_mu) self.worker.work() diff --git a/doc/manual/rtio.rst b/doc/manual/rtio.rst index 2344a9576..25ad9e0f1 100644 --- a/doc/manual/rtio.rst +++ b/doc/manual/rtio.rst @@ -36,7 +36,7 @@ The wall clock keeps running across experiments. Absolute timestamps can be large numbers. They are represented internally as 64-bit integers with a resolution of typically a nanosecond and a range of hundreds of years. Conversions between such a large integer number and a floating point representation can cause loss of precision through cancellation. -When computing the difference of absolute timestamps, use ``mu_to_seconds(t2-t1)``, not ``mu_to_seconds(t2)-mu_to_seconds(t1)`` (see :meth:`artiq.language.core.mu_to_seconds`). +When computing the difference of absolute timestamps, use ``self.core.mu_to_seconds(t2-t1)``, not ``self.core.mu_to_seconds(t2)-self.core.mu_to_seconds(t1)`` (see :meth:`artiq.coredevice.Core.mu_to_seconds`). When accumulating time, do it in machine units and not in SI units, so that rounding errors do not accumulate. The following basic example shows how to place output events on the timeline. From 3485c834296df3b2828b65038a7e02d4085dd360 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 06:40:47 +0000 Subject: [PATCH 39/47] Fix tests. --- artiq/test/coredevice/test_rtio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index c55e44c1f..55e91f16f 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -403,7 +403,7 @@ class CoredeviceTest(ExperimentCase): self.execute(TimeKeepsRunning) t2 = self.dataset_mgr.get("time_at_start") - dead_time = self.core.mu_to_seconds(t2 - t1, self.device_mgr.get("core")) + dead_time = self.device_mgr.get("core").mu_to_seconds(t2 - t1) print(dead_time) self.assertGreater(dead_time, 1*ms) self.assertLess(dead_time, 2500*ms) From 35f4449ef249150fe042daaa7a40dca682667535 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 13:08:03 +0000 Subject: [PATCH 40/47] inferencer: significantly improve the op-assignment diagnostic. Before this commit, it displayed incorrect output if an error appeared on 2nd run and beyond, and displayed messages for trying to do "num32 -= num64" that made very little sense. --- artiq/compiler/transforms/inferencer.py | 41 +++++++++++++---------- artiq/test/lit/inferencer/error_coerce.py | 4 +-- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 716f8041b..41cee75d1 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -1043,22 +1043,10 @@ class Inferencer(algorithm.Visitor): if coerced: return_type, target_type, value_type = coerced - 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(node.value.type)}, - node.value.loc) - diag = diagnostic.Diagnostic("error", - "expression of type {typea} has to be coerced to {typeb}, " - "which makes assignment invalid", - {"typea": printer.name(node.target.type), - "typeb": printer.name(target_type)}, - node.op.loc, [node.target.loc], [note]) - self.engine.process(diag) - return + 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) @@ -1066,17 +1054,34 @@ class Inferencer(algorithm.Visitor): printer = types.TypePrinter() note = diagnostic.Diagnostic("note", "expression of type {typec}", - {"typec": printer.name(node.value.type)}, + {"typec": printer.name(orig_value_type)}, node.value.loc) diag = diagnostic.Diagnostic("error", "the result of this operation has type {typeb}, " - "which makes assignment to a slot of type {typea} invalid", + "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): diff --git a/artiq/test/lit/inferencer/error_coerce.py b/artiq/test/lit/inferencer/error_coerce.py index 8afb83e6b..c4f732e7e 100644 --- a/artiq/test/lit/inferencer/error_coerce.py +++ b/artiq/test/lit/inferencer/error_coerce.py @@ -28,10 +28,10 @@ # CHECK-L: ${LINE:+1}: error: cannot coerce list(elt='a) to a numeric type [] - 1.0 -# CHECK-L: ${LINE:+2}: error: expression of type numpy.int? has to be coerced to float, which makes assignment invalid +# 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 makes assignment to a slot of type (numpy.int?,) invalid +# 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,) From 53b7d59b6a1e86ad3bff2d910779a21188b1615e Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 13:21:32 +0000 Subject: [PATCH 41/47] analyses.constness: fix false positive on x[...]. --- artiq/compiler/analyses/constness.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/compiler/analyses/constness.py b/artiq/compiler/analyses/constness.py index 4fab07ea4..add1f7fac 100644 --- a/artiq/compiler/analyses/constness.py +++ b/artiq/compiler/analyses/constness.py @@ -17,6 +17,12 @@ class Constness(algorithm.Visitor): self.visit(node.targets) 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 + def visit_AttributeT(self, node): self.generic_visit(node) if self.in_assign: From 55ea68da7fd2cd49f6f9a9b713dba68d1264d36a Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 14:01:11 +0000 Subject: [PATCH 42/47] compiler: unbreak casts to int32/int64. --- artiq/compiler/builtins.py | 4 +- artiq/compiler/prelude.py | 2 + .../compiler/transforms/artiq_ir_generator.py | 3 +- artiq/compiler/transforms/inferencer.py | 43 ++++++++++--------- artiq/test/lit/inferencer/builtin_calls.py | 4 +- artiq/test/lit/inferencer/cast.py | 5 +++ .../lit/inferencer/error_builtin_calls.py | 4 -- artiq/test/lit/integration/builtin.py | 2 +- 8 files changed, 36 insertions(+), 31 deletions(-) create mode 100644 artiq/test/lit/inferencer/cast.py diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index 6ab7ffe15..3e82f955f 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -126,10 +126,10 @@ def fn_int(): return types.TConstructor(TInt()) def fn_int32(): - return types.TConstructor(TInt32()) + return types.TBuiltinFunction("int32") def fn_int64(): - return types.TConstructor(TInt64()) + return types.TBuiltinFunction("int64") def fn_float(): return types.TConstructor(TFloat()) diff --git a/artiq/compiler/prelude.py b/artiq/compiler/prelude.py index b0b8db762..f50e4f2fa 100644 --- a/artiq/compiler/prelude.py +++ b/artiq/compiler/prelude.py @@ -14,6 +14,8 @@ def globals(): "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(), diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 6ccd74f43..8e10b77de 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1599,7 +1599,8 @@ class ARTIQIRGenerator(algorithm.Visitor): return self.coerce_to_bool(arg) else: assert False - elif types.is_builtin(typ, "int"): + 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 \ diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 41cee75d1..b55dfa98d 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -622,14 +622,28 @@ class Inferencer(algorithm.Visitor): self._unify(node.type, builtins.TBool(), node.loc, None) - elif types.is_builtin(typ, "int"): - valid_forms = lambda: [ - valid_form("int() -> numpy.int?"), - valid_form("int(x:'a) -> numpy.int?"), - valid_form("int(x:'a, width=?) -> numpy.int?") - ] + 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, builtins.TInt(), + self._unify(node.type, result_typ, node.loc, None) if len(node.args) == 0 and len(node.keywords) == 0: @@ -639,20 +653,7 @@ class Inferencer(algorithm.Visitor): 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, builtins.TInt(), - node.loc, None) - elif len(node.args) == 1 and len(node.keywords) == 1 and \ - builtins.is_numeric(node.args[0].type) and \ - node.keywords[0].arg == 'width': - width = node.keywords[0].value - if not (isinstance(width, asttyped.NumT) and isinstance(width.n, int)): - diag = diagnostic.Diagnostic("error", - "the width argument of int() must be an integer literal", {}, - node.keywords[0].loc) - self.engine.process(diag) - return - - self._unify(node.type, builtins.TInt(types.TValue(width.n)), + self._unify(node.type, result_typ, node.loc, None) else: diagnose(valid_forms()) diff --git a/artiq/test/lit/inferencer/builtin_calls.py b/artiq/test/lit/inferencer/builtin_calls.py index c461d5a03..bd33dd140 100644 --- a/artiq/test/lit/inferencer/builtin_calls.py +++ b/artiq/test/lit/inferencer/builtin_calls.py @@ -13,8 +13,8 @@ int() # CHECK-L: int:(1.0:float):numpy.int? int(1.0) -# CHECK-L: int:(1.0:float, width=64:numpy.int?):numpy.int64 -int(1.0, width=64) +# CHECK-L: int64:(1.0:float):numpy.int64 +int64(1.0) # CHECK-L: float:():float float() diff --git a/artiq/test/lit/inferencer/cast.py b/artiq/test/lit/inferencer/cast.py new file mode 100644 index 000000000..0f9c4c8d9 --- /dev/null +++ b/artiq/test/lit/inferencer/cast.py @@ -0,0 +1,5 @@ +# RUN: %python -m artiq.compiler.testbench.inferencer +mono %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +# CHECK-L: numpy.int64 +int64(2)**32 diff --git a/artiq/test/lit/inferencer/error_builtin_calls.py b/artiq/test/lit/inferencer/error_builtin_calls.py index 172f01e8f..f3d8b7df8 100644 --- a/artiq/test/lit/inferencer/error_builtin_calls.py +++ b/artiq/test/lit/inferencer/error_builtin_calls.py @@ -1,10 +1,6 @@ # RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t # RUN: OutputCheck %s --file-to-check=%t -a = 1 -# CHECK-L: ${LINE:+1}: error: the width argument of int() must be an integer literal -int(1.0, width=a) - # CHECK-L: ${LINE:+1}: error: the argument of len() must be of an iterable type len(1) diff --git a/artiq/test/lit/integration/builtin.py b/artiq/test/lit/integration/builtin.py index dbb7e471c..1562edf57 100644 --- a/artiq/test/lit/integration/builtin.py +++ b/artiq/test/lit/integration/builtin.py @@ -7,7 +7,7 @@ assert bool() is False assert int() is 0 assert int(1.0) is 1 -#ARTIQ#assert int(1, width=64) << 40 is 1099511627776 +#ARTIQ#assert int64(1) << 40 is 1099511627776 #ARTIQ#assert float() is 0.0 #ARTIQ#assert float(1) is 1.0 From f4b76667689dee7c593bed0252f27b76f2e88c7b Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 11:55:44 +0000 Subject: [PATCH 43/47] coredevice.dds: reimplement fully in ARTIQ Python. This commit also drops AD9858 support from software. --- artiq/coredevice/analyzer.py | 37 +- artiq/coredevice/dds.py | 359 +++++++++++++----- artiq/coredevice/exceptions.py | 1 - artiq/dashboard/moninj.py | 4 +- artiq/examples/master/device_db.pyon | 15 +- .../master/repository/utilities/dds_setter.py | 2 +- artiq/gateware/targets/kc705.py | 1 - artiq/gateware/targets/pipistrello.py | 1 - artiq/runtime/Makefile | 2 +- artiq/runtime/dds.c | 263 ------------- artiq/runtime/dds.h | 70 ---- 11 files changed, 276 insertions(+), 479 deletions(-) delete mode 100644 artiq/runtime/dds.c delete mode 100644 artiq/runtime/dds.h diff --git a/artiq/coredevice/analyzer.py b/artiq/coredevice/analyzer.py index 6540a4acc..d98016a5b 100644 --- a/artiq/coredevice/analyzer.py +++ b/artiq/coredevice/analyzer.py @@ -182,10 +182,7 @@ class DDSHandler: self.vcd_manager.get_channel("dds/" + name + "/frequency", 64) dds_channel["vcd_phase"] = \ self.vcd_manager.get_channel("dds/" + name + "/phase", 64) - if self.dds_type == "AD9858": - dds_channel["ftw"] = [None, None, None, None] - dds_channel["pow"] = [None, None] - elif self.dds_type == "AD9914": + if self.dds_type == "DDSChannelAD9914": dds_channel["ftw"] = [None, None] dds_channel["pow"] = None self.dds_channels[dds_channel_nr] = dds_channel @@ -205,26 +202,6 @@ class DDSHandler: else: return {gpio} - def _decode_ad9858_write(self, message): - if message.address == 0x41: - self.selected_dds_channels = self._gpio_to_channels(message.data) - for dds_channel_nr in self.selected_dds_channels: - dds_channel = self.dds_channels[dds_channel_nr] - if message.address in range(0x0a, 0x0e): - dds_channel["ftw"][message.address - 0x0a] = message.data - elif message.address in range(0x0e, 0x10): - dds_channel["pow"][message.address - 0x0e] = message.data - elif message.address == 0x40: # FUD - if None not in dds_channel["ftw"]: - ftw = sum(x << i*8 - for i, x in enumerate(dds_channel["ftw"])) - frequency = ftw*self.sysclk/2**32 - dds_channel["vcd_frequency"].set_value_double(frequency) - if None not in dds_channel["pow"]: - pow = dds_channel["pow"][0] | (dds_channel["pow"][1] & 0x3f) << 8 - phase = pow/2**14 - dds_channel["vcd_phase"].set_value_double(phase) - def _decode_ad9914_write(self, message): if message.address == 0x81: self.selected_dds_channels = self._gpio_to_channels(message.data) @@ -251,9 +228,7 @@ class DDSHandler: logger.debug("DDS write @%d 0x%04x to 0x%02x, selected channels: %s", message.timestamp, message.data, message.address, self.selected_dds_channels) - if self.dds_type == "AD9858": - self._decode_ad9858_write(message) - elif self.dds_type == "AD9914": + if self.dds_type == "DDSChannelAD9914": self._decode_ad9914_write(message) @@ -312,7 +287,7 @@ def get_single_device_argument(devices, module, cls, argument): for desc in devices.values(): if isinstance(desc, dict) and desc["type"] == "local": if (desc["module"] == module - and desc["class"] == cls): + and desc["class"] in cls): if ref_period is None: ref_period = desc["arguments"][argument] else: @@ -322,12 +297,12 @@ def get_single_device_argument(devices, module, cls, argument): def get_ref_period(devices): return get_single_device_argument(devices, "artiq.coredevice.core", - "Core", "ref_period") + ("Core",), "ref_period") def get_dds_sysclk(devices): return get_single_device_argument(devices, "artiq.coredevice.dds", - "CoreDDS", "sysclk") + ("DDSGroupAD9914",), "sysclk") def create_channel_handlers(vcd_manager, devices, ref_period, @@ -344,7 +319,7 @@ def create_channel_handlers(vcd_manager, devices, ref_period, channel = desc["arguments"]["channel"] channel_handlers[channel] = TTLClockGenHandler(vcd_manager, name, ref_period) if (desc["module"] == "artiq.coredevice.dds" - and desc["class"] in {"AD9858", "AD9914"}): + and desc["class"] in {"DDSChannelAD9914"}): dds_bus_channel = desc["arguments"]["bus_channel"] dds_channel = desc["arguments"]["channel"] if dds_bus_channel in channel_handlers: diff --git a/artiq/coredevice/dds.py b/artiq/coredevice/dds.py index 1437ff2df..a6d9c2dd1 100644 --- a/artiq/coredevice/dds.py +++ b/artiq/coredevice/dds.py @@ -1,56 +1,84 @@ from artiq.language.core import * from artiq.language.types import * from artiq.language.units import * -from numpy import int64 +from artiq.coredevice.rtio import rtio_output +from artiq.coredevice.exceptions import DDSError + +from numpy import int32, int64 -_PHASE_MODE_DEFAULT = -1 -# keep in sync with dds.h +_PHASE_MODE_DEFAULT = -1 PHASE_MODE_CONTINUOUS = 0 -PHASE_MODE_ABSOLUTE = 1 -PHASE_MODE_TRACKING = 2 +PHASE_MODE_ABSOLUTE = 1 +PHASE_MODE_TRACKING = 2 -@syscall(flags={"nowrite"}) -def dds_init(time_mu: TInt64, bus_channel: TInt32, channel: TInt32) -> TNone: - raise NotImplementedError("syscall not simulated") - -@syscall(flags={"nowrite"}) -def dds_init_sync(time_mu: TInt64, bus_channel: TInt32, - channel: TInt32, sync_delay: TInt32) -> TNone: - raise NotImplementedError("syscall not simulated") - -@syscall(flags={"nowrite"}) -def dds_set(time_mu: TInt64, bus_channel: TInt32, channel: TInt32, ftw: TInt32, - pow: TInt32, phase_mode: TInt32, amplitude: TInt32) -> TNone: - raise NotImplementedError("syscall not simulated") - -@syscall(flags={"nowrite"}) -def dds_batch_enter(time_mu: TInt64) -> TNone: - raise NotImplementedError("syscall not simulated") - -@syscall(flags={"nowrite"}) -def dds_batch_exit() -> TNone: - raise NotImplementedError("syscall not simulated") +class DDSParams: + def __init__(self): + self.bus_channel = 0 + self.channel = 0 + self.ftw = 0 + self.pow = 0 + self.phase_mode = 0 + self.amplitude = 0 -class _BatchContextManager: - kernel_invariants = {"core", "core_dds"} +class BatchContextManager: + kernel_invariants = {"core", "core_dds", "params"} def __init__(self, core_dds): self.core_dds = core_dds - self.core = self.core_dds.core + self.core = self.core_dds.core + self.active = False + self.params = [DDSParams() for _ in range(16)] + self.count = 0 + self.ref_time = int64(0) @kernel def __enter__(self): - self.core_dds.dds_batch_enter() + """Starts a DDS command batch. All DDS commands are buffered + after this call, until ``batch_exit`` is called. + + The time of execution of the DDS commands is the time cursor position + when the batch is entered.""" + if self.active: + raise DDSError("DDS batch entered twice") + + self.active = True + self.count = 0 + self.ref_time = now_mu() + + @kernel + def append(self, bus_channel, channel, ftw, pow, phase_mode, amplitude): + if self.count == len(self.params): + raise DDSError("Too many commands in DDS batch") + + params = self.params[self.count] + params.bus_channel = bus_channel + params.channel = channel + params.ftw = ftw + params.pow = pow + params.phase_mode = phase_mode + params.amplitude = amplitude + self.count += 1 @kernel def __exit__(self, type, value, traceback): - self.core_dds.dds_batch_exit() + """Ends a DDS command batch. All buffered DDS commands are issued + on the bus.""" + if not self.active: + raise DDSError("DDS batch exited twice") + + self.active = False + at_mu(self.ref_time - self.core_dds.batch_duration_mu()) + for i in range(self.count): + param = self.params[i] + self.core_dds.program(self.ref_time, + param.bus_channel, param.channel, param.ftw, + param.pow, param.phase_mode, param.amplitude) -class CoreDDS: +class DDSGroup: """Core device Direct Digital Synthesis (DDS) driver. Gives access to the DDS functionality of the core device. @@ -62,33 +90,77 @@ class CoreDDS: kernel_invariants = {"core", "sysclk", "batch"} def __init__(self, dmgr, sysclk, core_device="core"): - self.core = dmgr.get(core_device) + self.core = dmgr.get(core_device) self.sysclk = sysclk - self.batch = _BatchContextManager(self) + self.batch = BatchContextManager(self) @kernel - def dds_batch_enter(self): - """Starts a DDS command batch. All DDS commands are buffered - after this call, until ``batch_exit`` is called. - - The time of execution of the DDS commands is the time cursor position - when the batch is entered.""" - dds_batch_enter(now_mu()) + def batch_duration_mu(self): + raise NotImplementedError @kernel - def dds_batch_exit(self): - """Ends a DDS command batch. All buffered DDS commands are issued - on the bus.""" - dds_batch_exit() + def init(self, bus_channel, channel): + raise NotImplementedError + + @kernel + def program(self, ref_time, bus_channel, channel, ftw, pow, phase_mode, amplitude): + raise NotImplementedError + + @kernel + def set(self, bus_channel, channel, ftw, pow, phase_mode, amplitude): + if self.batch.active: + self.batch.append(bus_channel, channel, ftw, pow, phase_mode, amplitude) + else: + ref_time = now_mu() + at_mu(ref_time - self.program_duration_mu) + self.program(ref_time, + bus_channel, channel, ftw, pow, phase_mode, amplitude) + + @portable(flags={"fast-math"}) + def frequency_to_ftw(self, frequency): + """Returns the frequency tuning word corresponding to the given + frequency. + """ + return round(float(int64(2)**32*frequency/self.sysclk)) + + @portable(flags={"fast-math"}) + def ftw_to_frequency(self, ftw): + """Returns the frequency corresponding to the given frequency tuning + word. + """ + return ftw*self.sysclk/int64(2)**32 + + @portable(flags={"fast-math"}) + def turns_to_pow(self, turns): + """Returns the phase offset word corresponding to the given phase + in turns.""" + return round(float(turns*2**self.pow_width)) + + @portable(flags={"fast-math"}) + def pow_to_turns(self, pow): + """Returns the phase in turns corresponding to the given phase offset + word.""" + return pow/2**self.pow_width + + @portable(flags={"fast-math"}) + def amplitude_to_asf(self, amplitude): + """Returns amplitude scale factor corresponding to given amplitude.""" + return round(float(amplitude*0x0fff)) + + @portable(flags={"fast-math"}) + def asf_to_amplitude(self, asf): + """Returns the amplitude corresponding to the given amplitude scale + factor.""" + return asf/0x0fff -class _DDSGeneric: +class DDSChannel: """Core device Direct Digital Synthesis (DDS) channel driver. Controls one DDS channel managed directly by the core device's runtime. This class should not be used directly, instead, use the chip-specific - drivers such as ``AD9858`` and ``AD9914``. + drivers such as ``DDSChannelAD9914``. The time cursor is not modified by any function in this class. @@ -97,52 +169,15 @@ class _DDSGeneric: """ kernel_invariants = { - "core", "core_dds", "bus_channel", "channel", "pow_width" + "core", "core_dds", "bus_channel", "channel", } def __init__(self, dmgr, bus_channel, channel, core_dds_device="core_dds"): - self.core_dds = dmgr.get(core_dds_device) - self.core = self.core_dds.core + self.core_dds = dmgr.get(core_dds_device) + self.core = self.core_dds.core self.bus_channel = bus_channel - self.channel = channel - self.phase_mode = PHASE_MODE_CONTINUOUS - - @portable(flags=["fast-math"]) - def frequency_to_ftw(self, frequency): - """Returns the frequency tuning word corresponding to the given - frequency. - """ - return round(float(int64(2)**32*frequency/self.core_dds.sysclk)) - - @portable(flags=["fast-math"]) - def ftw_to_frequency(self, ftw): - """Returns the frequency corresponding to the given frequency tuning - word. - """ - return ftw*self.core_dds.sysclk/int64(2)**32 - - @portable(flags=["fast-math"]) - def turns_to_pow(self, turns): - """Returns the phase offset word corresponding to the given phase - in turns.""" - return round(float(turns*2**self.pow_width)) - - @portable(flags=["fast-math"]) - def pow_to_turns(self, pow): - """Returns the phase in turns corresponding to the given phase offset - word.""" - return pow/2**self.pow_width - - @portable(flags=["fast-math"]) - def amplitude_to_asf(self, amplitude): - """Returns amplitude scale factor corresponding to given amplitude.""" - return round(float(amplitude*0x0fff)) - - @portable(flags=["fast-math"]) - def asf_to_amplitude(self, asf): - """Returns the amplitude corresponding to the given amplitude scale - factor.""" - return asf/0x0fff + self.channel = channel + self.phase_mode = PHASE_MODE_CONTINUOUS @kernel def init(self): @@ -155,7 +190,7 @@ class _DDSGeneric: initializing multiple DDS channels is to call this function sequentially with a delay between the calls. 2ms provides a good timing margin.""" - dds_init(now_mu(), self.bus_channel, self.channel) + self.core_dds.init(self.bus_channel, self.channel) @kernel def set_phase_mode(self, phase_mode): @@ -197,29 +232,147 @@ class _DDSGeneric: """ if phase_mode == _PHASE_MODE_DEFAULT: phase_mode = self.phase_mode - dds_set(now_mu(), self.bus_channel, self.channel, - frequency, phase, phase_mode, amplitude) + self.core_dds.set(self.bus_channel, self.channel, frequency, phase, phase_mode, amplitude) @kernel def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT, amplitude=1.0): """Like ``set_mu``, but uses Hz and turns.""" - self.set_mu(self.frequency_to_ftw(frequency), - self.turns_to_pow(phase), phase_mode, - self.amplitude_to_asf(amplitude)) + self.set_mu(self.core_dds.frequency_to_ftw(frequency), + self.core_dds.turns_to_pow(phase), phase_mode, + self.core_dds.amplitude_to_asf(amplitude)) -class AD9858(_DDSGeneric): - """Driver for AD9858 DDS chips. See ``_DDSGeneric`` for a description +AD9914_REG_CFR1L = 0x01 +AD9914_REG_CFR1H = 0x03 +AD9914_REG_CFR2L = 0x05 +AD9914_REG_CFR2H = 0x07 +AD9914_REG_CFR3L = 0x09 +AD9914_REG_CFR3H = 0x0b +AD9914_REG_CFR4L = 0x0d +AD9914_REG_CFR4H = 0x0f +AD9914_REG_FTWL = 0x2d +AD9914_REG_FTWH = 0x2f +AD9914_REG_POW = 0x31 +AD9914_REG_ASF = 0x33 +AD9914_REG_USR0 = 0x6d +AD9914_FUD = 0x80 +AD9914_GPIO = 0x81 + + +class DDSGroupAD9914(DDSGroup): + """Driver for AD9914 DDS chips. See ``DDSGroup`` for a description of the functionality.""" - pow_width = 14 + kernel_invariants = DDSGroup.kernel_invariants.union({ + "pow_width", "rtio_period_mu", "sysclk_per_mu", "write_duration_mu", "dac_cal_duration_mu", + "init_duration_mu", "init_sync_duration_mu", "program_duration_mu", + "first_dds_bus_channel", "dds_channel_count", "continuous_phase_comp" + }) - -class AD9914(_DDSGeneric): - """Driver for AD9914 DDS chips. See ``_DDSGeneric`` for a description - of the functionality.""" pow_width = 16 + def __init__(self, *args, first_dds_bus_channel, dds_bus_count, dds_channel_count, **kwargs): + super().__init__(*args, **kwargs) + + self.first_dds_bus_channel = first_dds_bus_channel + self.dds_bus_count = dds_bus_count + self.dds_channel_count = dds_channel_count + + self.rtio_period_mu = int64(8) + self.sysclk_per_mu = int32(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 + self.init_duration_mu = 8 * self.write_duration_mu + self.dac_cal_duration_mu + self.init_sync_duration_mu = 16 * self.write_duration_mu + 2 * self.dac_cal_duration_mu + self.program_duration_mu = 6 * self.write_duration_mu + + self.continuous_phase_comp = [0] * (self.dds_bus_count * self.dds_channel_count) + + @kernel + def batch_duration_mu(self): + return self.batch.count * (self.program_duration_mu + + self.write_duration_mu) # + FUD time + + @kernel + def write(self, bus_channel, addr, data): + rtio_output(now_mu(), bus_channel, addr, data) + delay_mu(self.write_duration_mu) + + @kernel + def init(self, bus_channel, channel): + delay_mu(-self.init_duration_mu) + self.write(bus_channel, AD9914_GPIO, (1 << channel) << 1); + + self.write(bus_channel, AD9914_REG_CFR1H, 0x0000) # Enable cosine output + self.write(bus_channel, AD9914_REG_CFR2L, 0x8900) # Enable matched latency + self.write(bus_channel, AD9914_REG_CFR2H, 0x0080) # Enable profile mode + self.write(bus_channel, AD9914_REG_ASF, 0x0fff) # Set amplitude to maximum + self.write(bus_channel, AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration + self.write(bus_channel, AD9914_FUD, 0) + delay_mu(self.dac_cal_duration_mu) + self.write(bus_channel, AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration + self.write(bus_channel, AD9914_FUD, 0) + + @kernel + def init_sync(self, bus_channel, channel, sync_delay): + delay_mu(-self.init_sync_duration_mu) + self.write(bus_channel, AD9914_GPIO, (1 << channel) << 1) + + self.write(bus_channel, AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration + self.write(bus_channel, AD9914_FUD, 0) + delay_mu(self.dac_cal_duration_mu) + self.write(bus_channel, AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration + self.write(bus_channel, AD9914_FUD, 0) + self.write(bus_channel, AD9914_REG_CFR2L, 0x8b00) # Enable matched latency and sync_out + self.write(bus_channel, AD9914_FUD, 0) + # Set cal with sync and set sync_out and sync_in delay + self.write(bus_channel, AD9914_REG_USR0, 0x0840 | (sync_delay & 0x3f)) + self.write(bus_channel, AD9914_FUD, 0) + self.write(bus_channel, AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration + self.write(bus_channel, AD9914_FUD, 0) + delay_mu(self.dac_cal_duration_mu) + self.write(bus_channel, AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration + self.write(bus_channel, AD9914_FUD, 0) + self.write(bus_channel, AD9914_REG_CFR1H, 0x0000) # Enable cosine output + self.write(bus_channel, AD9914_REG_CFR2H, 0x0080) # Enable profile mode + self.write(bus_channel, AD9914_REG_ASF, 0x0fff) # Set amplitude to maximum + self.write(bus_channel, AD9914_FUD, 0) + + @kernel + def program(self, ref_time, bus_channel, channel, ftw, pow, phase_mode, amplitude): + self.write(bus_channel, AD9914_GPIO, (1 << channel) << 1) + + self.write(bus_channel, AD9914_REG_FTWL, ftw & 0xffff) + self.write(bus_channel, AD9914_REG_FTWH, (ftw >> 16) & 0xffff) + + # We need the RTIO fine timestamp clock to be phase-locked + # to DDS SYSCLK, and divided by an integer self.sysclk_per_mu. + dds_bus_index = bus_channel - self.first_dds_bus_channel + phase_comp_index = dds_bus_index * self.dds_channel_count + channel + if phase_mode == PHASE_MODE_CONTINUOUS: + # Do not clear phase accumulator on FUD + # Disable autoclear phase accumulator and enables OSK. + self.write(bus_channel, AD9914_REG_CFR1L, 0x0108) + pow += self.continuous_phase_comp[phase_comp_index] + else: + # Clear phase accumulator on FUD + # Enable autoclear phase accumulator and enables OSK. + self.write(bus_channel, AD9914_REG_CFR1L, 0x2108) + fud_time = now_mu() + 2 * self.write_duration_mu + pow -= int32((ref_time - fud_time) * self.sysclk_per_mu * ftw >> (32 - self.pow_width)) + if phase_mode == PHASE_MODE_TRACKING: + pow += int32(ref_time * self.sysclk_per_mu * ftw >> (32 - self.pow_width)) + self.continuous_phase_comp[phase_comp_index] = pow + + self.write(bus_channel, AD9914_REG_POW, pow) + self.write(bus_channel, AD9914_REG_ASF, amplitude) + self.write(bus_channel, AD9914_FUD, 0) + + +class DDSChannelAD9914(DDSChannel): + """Driver for AD9914 DDS chips. See ``DDSChannel`` for a description + of the functionality.""" @kernel def init_sync(self, sync_delay=0): """Resets and initializes the DDS channel as well as configures @@ -237,4 +390,4 @@ class AD9914(_DDSGeneric): :param sync_delay: integer from 0 to 0x3f that sets the value of SYNC_OUT (bits 3-5) and SYNC_IN (bits 0-2) delay ADJ bits. """ - dds_init_sync(now_mu(), self.bus_channel, self.channel, sync_delay) + self.core_dds.init_sync(self.bus_channel, self.channel, sync_delay) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 9137a7ffe..5ba1c5f43 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -125,7 +125,6 @@ class DDSError(Exception): when too many commands are batched, and when DDS channel settings are incorrect. """ - artiq_builtin = True class I2CError(Exception): """Raised with a I2C transaction fails.""" diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index 22c0bb963..6baa31ade 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -219,10 +219,10 @@ class _DeviceManager: self.ttl_widgets[k] = widget self.ttl_cb() if (v["module"] == "artiq.coredevice.dds" - and v["class"] == "CoreDDS"): + and v["class"] == "DDSGroupAD9914"): self.dds_sysclk = v["arguments"]["sysclk"] if (v["module"] == "artiq.coredevice.dds" - and v["class"] in {"AD9858", "AD9914"}): + and v["class"] in {"DDSChannelAD9914"}): bus_channel = v["arguments"]["bus_channel"] channel = v["arguments"]["channel"] widget = _DDSWidget( diff --git a/artiq/examples/master/device_db.pyon b/artiq/examples/master/device_db.pyon index f5811ee34..5803a3e80 100644 --- a/artiq/examples/master/device_db.pyon +++ b/artiq/examples/master/device_db.pyon @@ -23,8 +23,13 @@ "core_dds": { "type": "local", "module": "artiq.coredevice.dds", - "class": "CoreDDS", - "arguments": {"sysclk": 3e9} + "class": "DDSGroupAD9914", + "arguments": { + "sysclk": 3e9, + "first_dds_bus_channel": 26, + "dds_bus_count": 2, + "dds_channel_count": 3 + } }, "i2c_switch": { @@ -136,20 +141,20 @@ "dds0": { "type": "local", "module": "artiq.coredevice.dds", - "class": "AD9914", + "class": "DDSChannelAD9914", "arguments": {"bus_channel": 26, "channel": 0}, "comment": "Comments work in DDS panel as well" }, "dds1": { "type": "local", "module": "artiq.coredevice.dds", - "class": "AD9914", + "class": "DDSChannelAD9914", "arguments": {"bus_channel": 26, "channel": 1} }, "dds2": { "type": "local", "module": "artiq.coredevice.dds", - "class": "AD9914", + "class": "DDSChannelAD9914", "arguments": {"bus_channel": 26, "channel": 2} }, diff --git a/artiq/examples/master/repository/utilities/dds_setter.py b/artiq/examples/master/repository/utilities/dds_setter.py index 1e8f4066d..ef13b1bd3 100644 --- a/artiq/examples/master/repository/utilities/dds_setter.py +++ b/artiq/examples/master/repository/utilities/dds_setter.py @@ -15,7 +15,7 @@ class DDSSetter(EnvExperiment): if (isinstance(v, dict) and v["type"] == "local" and v["module"] == "artiq.coredevice.dds" - and v["class"] in {"AD9858", "AD9914"}): + and v["class"] in {"DDSChannelAD9914"}): self.dds[k] = { "driver": self.get_device(k), "frequency": self.get_argument( diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index b6b04461b..a70e33814 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -144,7 +144,6 @@ class _NIST_Ions(MiniSoC, AMPSoC): self.csr_devices.append("rtio_crg") self.submodules.rtio = rtio.RTIO(rtio_channels) self.register_kernel_cpu_csrdevice("rtio") - self.config["RTIO_FINE_TS_WIDTH"] = self.rtio.fine_ts_width self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") diff --git a/artiq/gateware/targets/pipistrello.py b/artiq/gateware/targets/pipistrello.py index a0a5f0134..88c5fa017 100755 --- a/artiq/gateware/targets/pipistrello.py +++ b/artiq/gateware/targets/pipistrello.py @@ -225,7 +225,6 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd # RTIO logic self.submodules.rtio = rtio.RTIO(rtio_channels) self.register_kernel_cpu_csrdevice("rtio") - self.config["RTIO_FINE_TS_WIDTH"] = self.rtio.fine_ts_width self.config["DDS_RTIO_CLK_RATIO"] = 8 >> self.rtio.fine_ts_width self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") diff --git a/artiq/runtime/Makefile b/artiq/runtime/Makefile index e8936fdf4..797123c2c 100644 --- a/artiq/runtime/Makefile +++ b/artiq/runtime/Makefile @@ -4,7 +4,7 @@ include $(MISOC_DIRECTORY)/software/common.mak PYTHON ?= python3.5 OBJECTS := flash_storage.o main.o -OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o rtio.o dds.o i2c.o +OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o rtio.o i2c.o RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug CORE_IO_COMMIT := d40c593f42fafbac1ff3d827f6df96338b5b7d8b diff --git a/artiq/runtime/dds.c b/artiq/runtime/dds.c deleted file mode 100644 index 5b221ecf9..000000000 --- a/artiq/runtime/dds.c +++ /dev/null @@ -1,263 +0,0 @@ -#include - -#if ((defined CONFIG_RTIO_DDS_COUNT) && (CONFIG_RTIO_DDS_COUNT > 0)) - -#include - -#include "artiq_personality.h" -#include "rtio.h" -#include "dds.h" - -#define DURATION_WRITE (5 << CONFIG_RTIO_FINE_TS_WIDTH) - -#if defined CONFIG_DDS_AD9858 -/* Assume 8-bit bus */ -#define DURATION_INIT (7*DURATION_WRITE) /* not counting FUD */ -#define DURATION_PROGRAM (8*DURATION_WRITE) /* not counting FUD */ - -#elif defined CONFIG_DDS_AD9914 -/* Assume 16-bit bus */ -/* DAC calibration takes max. 1ms as per datasheet */ -#define DURATION_DAC_CAL (147000 << CONFIG_RTIO_FINE_TS_WIDTH) -/* not counting final FUD */ -#define DURATION_INIT (8*DURATION_WRITE + DURATION_DAC_CAL) -#define DURATION_INIT_SYNC (16*DURATION_WRITE + 2*DURATION_DAC_CAL) -#define DURATION_PROGRAM (6*DURATION_WRITE) /* not counting FUD */ - -#else -#error Unknown DDS configuration -#endif - -#define DDS_WRITE(addr, data) do { \ - rtio_output(now, bus_channel, addr, data); \ - now += DURATION_WRITE; \ - } while(0) - -void dds_init(long long int timestamp, int bus_channel, int channel) -{ - long long int now; - - now = timestamp - DURATION_INIT; - -#ifdef CONFIG_DDS_ONEHOT_SEL - channel = 1 << channel; -#endif - channel <<= 1; - DDS_WRITE(DDS_GPIO, channel); -#ifndef CONFIG_DDS_AD9914 - /* - * Resetting a AD9914 intermittently crashes it. It does not produce any - * output until power-cycled. - * Increasing the reset pulse length and the delay until the first write - * to 300ns do not solve the problem. - * The chips seem fine without a reset. - */ - DDS_WRITE(DDS_GPIO, channel | 1); /* reset */ - DDS_WRITE(DDS_GPIO, channel); -#endif - -#ifdef CONFIG_DDS_AD9858 - /* - * 2GHz divider disable - * SYNCLK disable - * Mixer power-down - * Phase detect power down - */ - DDS_WRITE(DDS_CFR0, 0x78); - DDS_WRITE(DDS_CFR1, 0x00); - DDS_WRITE(DDS_CFR2, 0x00); - DDS_WRITE(DDS_CFR3, 0x00); - DDS_WRITE(DDS_FUD, 0); -#endif - -#ifdef CONFIG_DDS_AD9914 - DDS_WRITE(DDS_CFR1H, 0x0000); /* Enable cosine output */ - DDS_WRITE(DDS_CFR2L, 0x8900); /* Enable matched latency */ - DDS_WRITE(DDS_CFR2H, 0x0080); /* Enable profile mode */ - DDS_WRITE(DDS_ASF, 0x0fff); /* Set amplitude to maximum */ - DDS_WRITE(DDS_CFR4H, 0x0105); /* Enable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); - now += DURATION_DAC_CAL; - DDS_WRITE(DDS_CFR4H, 0x0005); /* Disable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); -#endif -} - -void dds_init_sync(long long int timestamp, int bus_channel, int channel, int sync_delay) -{ -#ifdef CONFIG_DDS_AD9914 - long long int now; - - now = timestamp - DURATION_INIT_SYNC; - -#ifdef CONFIG_DDS_ONEHOT_SEL - channel = 1 << channel; -#endif - channel <<= 1; - DDS_WRITE(DDS_GPIO, channel); - - DDS_WRITE(DDS_CFR4H, 0x0105); /* Enable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); - now += DURATION_DAC_CAL; - DDS_WRITE(DDS_CFR4H, 0x0005); /* Disable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); - DDS_WRITE(DDS_CFR2L, 0x8b00); /* Enable matched latency and sync_out*/ - DDS_WRITE(DDS_FUD, 0); - /* Set cal with sync and set sync_out and sync_in delay */ - DDS_WRITE(DDS_USR0, 0x0840 | (sync_delay & 0x3f)); - DDS_WRITE(DDS_FUD, 0); - DDS_WRITE(DDS_CFR4H, 0x0105); /* Enable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); - now += DURATION_DAC_CAL; - DDS_WRITE(DDS_CFR4H, 0x0005); /* Disable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); - DDS_WRITE(DDS_CFR1H, 0x0000); /* Enable cosine output */ - DDS_WRITE(DDS_CFR2H, 0x0080); /* Enable profile mode */ - DDS_WRITE(DDS_ASF, 0x0fff); /* Set amplitude to maximum */ - DDS_WRITE(DDS_FUD, 0); -#endif -} - -/* Compensation to keep phase continuity when switching from absolute or tracking - * to continuous phase mode. */ -static unsigned int continuous_phase_comp[CONFIG_RTIO_DDS_COUNT][CONFIG_DDS_CHANNELS_PER_BUS]; - -static void dds_set_one(long long int now, long long int ref_time, - int bus_channel, int channel, - unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude) -{ - unsigned int channel_enc; - - if((channel < 0) || (channel >= CONFIG_DDS_CHANNELS_PER_BUS)) - artiq_raise_from_c("DDSError", "Attempted to set invalid DDS channel", 0, 0, 0); - if((bus_channel < CONFIG_RTIO_FIRST_DDS_CHANNEL) - || (bus_channel >= (CONFIG_RTIO_FIRST_DDS_CHANNEL+CONFIG_RTIO_DDS_COUNT))) - artiq_raise_from_c("DDSError", "Attempted to use invalid DDS bus", 0, 0, 0); - -#ifdef CONFIG_DDS_ONEHOT_SEL - channel_enc = 1 << channel; -#else - channel_enc = channel; -#endif - DDS_WRITE(DDS_GPIO, channel_enc << 1); - -#ifdef CONFIG_DDS_AD9858 - DDS_WRITE(DDS_FTW0, ftw & 0xff); - DDS_WRITE(DDS_FTW1, (ftw >> 8) & 0xff); - DDS_WRITE(DDS_FTW2, (ftw >> 16) & 0xff); - DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff); -#endif - -#ifdef CONFIG_DDS_AD9914 - DDS_WRITE(DDS_FTWL, ftw & 0xffff); - DDS_WRITE(DDS_FTWH, (ftw >> 16) & 0xffff); -#endif - - /* We need the RTIO fine timestamp clock to be phase-locked - * to DDS SYSCLK, and divided by an integer CONFIG_DDS_RTIO_CLK_RATIO. - */ - if(phase_mode == PHASE_MODE_CONTINUOUS) { - /* Do not clear phase accumulator on FUD */ -#ifdef CONFIG_DDS_AD9858 - DDS_WRITE(DDS_CFR2, 0x00); -#endif -#ifdef CONFIG_DDS_AD9914 - /* Disable autoclear phase accumulator and enables OSK. */ - DDS_WRITE(DDS_CFR1L, 0x0108); -#endif - pow += continuous_phase_comp[bus_channel-CONFIG_RTIO_FIRST_DDS_CHANNEL][channel]; - } else { - long long int fud_time; - - /* Clear phase accumulator on FUD */ -#ifdef CONFIG_DDS_AD9858 - DDS_WRITE(DDS_CFR2, 0x40); -#endif -#ifdef CONFIG_DDS_AD9914 - /* Enable autoclear phase accumulator and enables OSK. */ - DDS_WRITE(DDS_CFR1L, 0x2108); -#endif - fud_time = now + 2*DURATION_WRITE; - pow -= (ref_time - fud_time)*CONFIG_DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH); - if(phase_mode == PHASE_MODE_TRACKING) - pow += ref_time*CONFIG_DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH); - continuous_phase_comp[bus_channel-CONFIG_RTIO_FIRST_DDS_CHANNEL][channel] = pow; - } - -#ifdef CONFIG_DDS_AD9858 - DDS_WRITE(DDS_POW0, pow & 0xff); - DDS_WRITE(DDS_POW1, (pow >> 8) & 0x3f); -#endif -#ifdef CONFIG_DDS_AD9914 - DDS_WRITE(DDS_POW, pow); -#endif -#ifdef CONFIG_DDS_AD9914 - DDS_WRITE(DDS_ASF, amplitude); -#endif - DDS_WRITE(DDS_FUD, 0); -} - -struct dds_set_params { - int bus_channel; - int channel; - unsigned int ftw; - unsigned int pow; - int phase_mode; - unsigned int amplitude; -}; - -static int batch_mode; -static int batch_count; -static long long int batch_ref_time; -static struct dds_set_params batch[DDS_MAX_BATCH]; - -void dds_batch_enter(long long int timestamp) -{ - if(batch_mode) - artiq_raise_from_c("DDSError", "DDS batch entered twice", 0, 0, 0); - batch_mode = 1; - batch_count = 0; - batch_ref_time = timestamp; -} - -void dds_batch_exit(void) -{ - long long int now; - int i; - - if(!batch_mode) - artiq_raise_from_c("DDSError", "DDS batch exited twice", 0, 0, 0); - batch_mode = 0; - /* + FUD time */ - now = batch_ref_time - batch_count*(DURATION_PROGRAM + DURATION_WRITE); - for(i=0;i= DDS_MAX_BATCH) - artiq_raise_from_c("DDSError", "Too many commands in DDS batch", 0, 0, 0); - /* timestamp parameter ignored (determined by batch) */ - batch[batch_count].bus_channel = bus_channel; - batch[batch_count].channel = channel; - batch[batch_count].ftw = ftw; - batch[batch_count].pow = pow; - batch[batch_count].phase_mode = phase_mode; - batch[batch_count].amplitude = amplitude; - batch_count++; - } else { - dds_set_one(timestamp - DURATION_PROGRAM, timestamp, - bus_channel, channel, - ftw, pow, phase_mode, amplitude); - } -} - -#endif /* CONFIG_RTIO_DDS_COUNT */ diff --git a/artiq/runtime/dds.h b/artiq/runtime/dds.h deleted file mode 100644 index 8cca5cb74..000000000 --- a/artiq/runtime/dds.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef __DDS_H -#define __DDS_H - -#include -#include -#include - -#if ((defined CONFIG_RTIO_DDS_COUNT) && (CONFIG_RTIO_DDS_COUNT > 0)) - -/* Maximum number of commands in a batch */ -#define DDS_MAX_BATCH 16 - -#ifdef CONFIG_DDS_AD9858 -#define DDS_CFR0 0x00 -#define DDS_CFR1 0x01 -#define DDS_CFR2 0x02 -#define DDS_CFR3 0x03 -#define DDS_FTW0 0x0a -#define DDS_FTW1 0x0b -#define DDS_FTW2 0x0c -#define DDS_FTW3 0x0d -#define DDS_POW0 0x0e -#define DDS_POW1 0x0f -#define DDS_FUD 0x40 -#define DDS_GPIO 0x41 -#endif - -#ifdef CONFIG_DDS_AD9914 -#define DDS_CFR1L 0x01 -#define DDS_CFR1H 0x03 -#define DDS_CFR2L 0x05 -#define DDS_CFR2H 0x07 -#define DDS_CFR3L 0x09 -#define DDS_CFR3H 0x0b -#define DDS_CFR4L 0x0d -#define DDS_CFR4H 0x0f -#define DDS_FTWL 0x2d -#define DDS_FTWH 0x2f -#define DDS_POW 0x31 -#define DDS_ASF 0x33 -#define DDS_USR0 0x6d -#define DDS_FUD 0x80 -#define DDS_GPIO 0x81 -#endif - -#ifdef CONFIG_DDS_AD9858 -#define DDS_POW_WIDTH 14 -#endif - -#ifdef CONFIG_DDS_AD9914 -#define DDS_POW_WIDTH 16 -#endif - -enum { - PHASE_MODE_CONTINUOUS = 0, - PHASE_MODE_ABSOLUTE = 1, - PHASE_MODE_TRACKING = 2 -}; - -void dds_init(long long int timestamp, int bus_channel, int channel); -void dds_init_sync(long long int timestamp, int bus_channel, int channel, - int sync_delay); -void dds_batch_enter(long long int timestamp); -void dds_batch_exit(void); -void dds_set(long long int timestamp, int bus_channel, int channel, - unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude); - -#endif /* CONFIG_RTIO_DDS_COUNT */ - -#endif /* __DDS_H */ From 5e8888d5f3f33410bb6407017828d8d7b39146cb Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 15:13:55 +0000 Subject: [PATCH 44/47] Fully drop AD9858 and kc705-nist_qc1 support (closes #576). --- artiq/gateware/nist_qc1.py | 40 ---------------- artiq/gateware/rtio/phy/dds.py | 5 -- artiq/gateware/targets/kc705.py | 66 ++------------------------- artiq/gateware/targets/pipistrello.py | 13 ------ artiq/runtime.rs/libksupport/api.rs | 11 ----- conda/artiq-kc705-nist_qc1/build.sh | 14 ------ conda/artiq-kc705-nist_qc1/meta.yaml | 27 ----------- doc/manual/core_device.rst | 31 +------------ doc/manual/installing.rst | 5 +- doc/manual/installing_from_source.rst | 2 +- 10 files changed, 9 insertions(+), 205 deletions(-) delete mode 100644 conda/artiq-kc705-nist_qc1/build.sh delete mode 100644 conda/artiq-kc705-nist_qc1/meta.yaml diff --git a/artiq/gateware/nist_qc1.py b/artiq/gateware/nist_qc1.py index 918ac0be9..986aa141f 100644 --- a/artiq/gateware/nist_qc1.py +++ b/artiq/gateware/nist_qc1.py @@ -52,43 +52,3 @@ papilio_adapter_io = [ Subsignal("rst_n", Pins("A:3")), IOStandard("LVTTL")), ] - - -fmc_adapter_io = [ - ("pmt", 0, Pins("LPC:LA20_N"), IOStandard("LVTTL")), - ("pmt", 1, Pins("LPC:LA24_P"), IOStandard("LVTTL")), - - ("ttl", 0, Pins("LPC:LA21_P"), IOStandard("LVTTL")), - ("ttl", 1, Pins("LPC:LA25_P"), IOStandard("LVTTL")), - ("ttl", 2, Pins("LPC:LA21_N"), IOStandard("LVTTL")), - ("ttl", 3, Pins("LPC:LA25_N"), IOStandard("LVTTL")), - ("ttl", 4, Pins("LPC:LA22_P"), IOStandard("LVTTL")), - ("ttl", 5, Pins("LPC:LA26_P"), IOStandard("LVTTL")), - ("ttl", 6, Pins("LPC:LA22_N"), IOStandard("LVTTL")), - ("ttl", 7, Pins("LPC:LA26_N"), IOStandard("LVTTL")), - ("ttl", 8, Pins("LPC:LA23_P"), IOStandard("LVTTL")), - ("ttl", 9, Pins("LPC:LA27_P"), IOStandard("LVTTL")), - ("ttl", 10, Pins("LPC:LA23_N"), IOStandard("LVTTL")), - ("ttl", 11, Pins("LPC:LA27_N"), IOStandard("LVTTL")), - ("ttl", 12, Pins("LPC:LA00_CC_P"), IOStandard("LVTTL")), - ("ttl", 13, Pins("LPC:LA10_P"), IOStandard("LVTTL")), - ("ttl", 14, Pins("LPC:LA00_CC_N"), IOStandard("LVTTL")), - ("ttl", 15, Pins("LPC:LA10_N"), IOStandard("LVTTL")), - ("ttl_l_tx_en", 0, Pins("LPC:LA11_P"), IOStandard("LVTTL")), - ("ttl_h_tx_en", 0, Pins("LPC:LA01_CC_P"), IOStandard("LVTTL")), - - ("dds", 0, - Subsignal("a", Pins("LPC:LA04_N LPC:LA14_N LPC:LA05_P LPC:LA15_P " - "LPC:LA05_N LPC:LA15_N")), - Subsignal("d", Pins("LPC:LA06_P LPC:LA16_P LPC:LA06_N LPC:LA16_N " - "LPC:LA07_P LPC:LA17_CC_P LPC:LA07_N " - "LPC:LA17_CC_N")), - Subsignal("sel", Pins("LPC:LA12_N LPC:LA03_P LPC:LA13_P LPC:LA03_N " - "LPC:LA13_N")), - Subsignal("p", Pins("LPC:LA11_N LPC:LA02_P")), - Subsignal("fud_n", Pins("LPC:LA14_P")), - Subsignal("wr_n", Pins("LPC:LA04_P")), - Subsignal("rd_n", Pins("LPC:LA02_N")), - Subsignal("rst_n", Pins("LPC:LA12_P")), - IOStandard("LVTTL")), -] diff --git a/artiq/gateware/rtio/phy/dds.py b/artiq/gateware/rtio/phy/dds.py index c19f3c588..76666f809 100644 --- a/artiq/gateware/rtio/phy/dds.py +++ b/artiq/gateware/rtio/phy/dds.py @@ -56,11 +56,6 @@ class _AD9xxx(Module): for c, (probe, ftw) in enumerate(zip(self.probes, ftws))]) -class AD9858(_AD9xxx): - def __init__(self, *args, **kwargs): - _AD9xxx.__init__(self, 0x0a, *args, **kwargs) - - class AD9914(_AD9xxx): def __init__(self, *args, **kwargs): _AD9xxx.__init__(self, 0x2d, *args, **kwargs) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index a70e33814..d7672b435 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -17,7 +17,7 @@ from misoc.targets.kc705 import MiniSoC, soc_kc705_args, soc_kc705_argdict from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.soc import AMPSoC, build_artiq_soc -from artiq.gateware import rtio, nist_qc1, nist_clock, nist_qc2 +from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi from artiq import __version__ as artiq_version @@ -158,62 +158,6 @@ class _NIST_Ions(MiniSoC, AMPSoC): self.csr_devices.append("rtio_analyzer") -class NIST_QC1(_NIST_Ions): - """ - NIST QC1 hardware, as used in the Penning lab, with FMC to SCSI cables - adapter. - """ - def __init__(self, cpu_type="or1k", **kwargs): - _NIST_Ions.__init__(self, cpu_type, **kwargs) - - platform = self.platform - platform.add_extension(nist_qc1.fmc_adapter_io) - - self.comb += [ - platform.request("ttl_l_tx_en").eq(1), - platform.request("ttl_h_tx_en").eq(1) - ] - - rtio_channels = [] - for i in range(2): - phy = ttl_serdes_7series.Inout_8X(platform.request("pmt", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) - for i in range(15): - phy = ttl_serdes_7series.Output_8X(platform.request("ttl", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - phy = ttl_serdes_7series.Inout_8X(platform.request("user_sma_gpio_n_33")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) - phy = ttl_simple.Output(platform.request("user_led", 2)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels) - - phy = ttl_simple.ClockGen(platform.request("ttl", 15)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels) - self.config["RTIO_DDS_COUNT"] = 1 - self.config["DDS_CHANNELS_PER_BUS"] = 8 - self.config["DDS_AD9858"] = None - phy = dds.AD9858(platform.request("dds"), 8) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, - ofifo_depth=512, - ififo_depth=4)) - - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) - - self.add_rtio(rtio_channels) - assert self.rtio.fine_ts_width <= 3 - self.config["DDS_RTIO_CLK_RATIO"] = 8 >> self.rtio.fine_ts_width - - class NIST_CLOCK(_NIST_Ions): """ NIST clock hardware, with old backplane and 11 DDS channels @@ -372,19 +316,17 @@ class NIST_QC2(_NIST_Ions): def main(): parser = argparse.ArgumentParser( description="ARTIQ core device builder / KC705 " - "+ NIST Ions QC1/CLOCK/QC2 hardware adapters") + "+ NIST Ions CLOCK/QC2 hardware adapters") builder_args(parser) soc_kc705_args(parser) parser.add_argument("-H", "--hw-adapter", default="nist_clock", help="hardware adapter type: " - "nist_qc1/nist_clock/nist_qc2 " + "nist_clock/nist_qc2 " "(default: %(default)s)") args = parser.parse_args() hw_adapter = args.hw_adapter.lower() - if hw_adapter == "nist_qc1": - cls = NIST_QC1 - elif hw_adapter == "nist_clock": + if hw_adapter == "nist_clock": cls = NIST_CLOCK elif hw_adapter == "nist_qc2": cls = NIST_QC2 diff --git a/artiq/gateware/targets/pipistrello.py b/artiq/gateware/targets/pipistrello.py index 88c5fa017..52fb20046 100755 --- a/artiq/gateware/targets/pipistrello.py +++ b/artiq/gateware/targets/pipistrello.py @@ -206,19 +206,6 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd rtio_channels.append(rtio.Channel.from_phy( phy, ofifo_depth=64, ififo_depth=64)) - self.config["HAS_DDS"] = None - self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels) - self.config["RTIO_DDS_COUNT"] = 1 - self.config["DDS_CHANNELS_PER_BUS"] = 8 - self.config["DDS_AD9858"] = None - dds_pins = platform.request("dds") - self.comb += dds_pins.p.eq(0) - phy = dds.AD9858(dds_pins, 8) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, - ofifo_depth=128, - ififo_depth=4)) - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) diff --git a/artiq/runtime.rs/libksupport/api.rs b/artiq/runtime.rs/libksupport/api.rs index f30b099b0..82448c744 100644 --- a/artiq/runtime.rs/libksupport/api.rs +++ b/artiq/runtime.rs/libksupport/api.rs @@ -105,17 +105,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(rtio_input_timestamp), api!(rtio_input_data), - #[cfg(has_dds)] - api!(dds_init), - #[cfg(has_dds)] - api!(dds_init_sync), - #[cfg(has_dds)] - api!(dds_batch_enter), - #[cfg(has_dds)] - api!(dds_batch_exit), - #[cfg(has_dds)] - api!(dds_set), - api!(i2c_init), api!(i2c_start), api!(i2c_stop), diff --git a/conda/artiq-kc705-nist_qc1/build.sh b/conda/artiq-kc705-nist_qc1/build.sh deleted file mode 100644 index 855f2bdf3..000000000 --- a/conda/artiq-kc705-nist_qc1/build.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -BUILD_SETTINGS_FILE=$HOME/.m-labs/build_settings.sh -[ -f $BUILD_SETTINGS_FILE ] && . $BUILD_SETTINGS_FILE - -SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kc705-nist_qc1 -mkdir -p $SOC_PREFIX - -$PYTHON -m artiq.gateware.targets.kc705 -H nist_qc1 --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE -cp misoc_nist_qc1_kc705/gateware/top.bit $SOC_PREFIX -cp misoc_nist_qc1_kc705/software/bios/bios.bin $SOC_PREFIX -cp misoc_nist_qc1_kc705/software/runtime/runtime.fbi $SOC_PREFIX - -wget -P $SOC_PREFIX https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/master/bscan_spi_xc7k325t.bit diff --git a/conda/artiq-kc705-nist_qc1/meta.yaml b/conda/artiq-kc705-nist_qc1/meta.yaml deleted file mode 100644 index 2ee0b5b54..000000000 --- a/conda/artiq-kc705-nist_qc1/meta.yaml +++ /dev/null @@ -1,27 +0,0 @@ -package: - name: artiq-kc705-nist_qc1 - version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} - -source: - git_url: ../.. - -build: - noarch_python: true - number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} - string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_DESCRIBE_HASH", "")[1:] }} - -requirements: - build: - - migen 0.5.dev - - misoc 0.5.dev - - llvm-or1k - - binutils-or1k-linux >=2.27 - - rust-core-or1k - - cargo - run: - - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_DESCRIBE_HASH")[1:]) if "GIT_DESCRIBE_TAG" in environ else "" }} - -about: - home: https://m-labs.hk/artiq - license: GPL - summary: 'Bitstream, BIOS and runtime for NIST_QC1 on the KC705 board' diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index eae66caa2..9f3bf48a7 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -29,13 +29,13 @@ All boards have a serial interface running at 115200bps 8-N-1 that can be used f KC705 ----- -The main target board for the ARTIQ core device is the KC705 development board from Xilinx. It supports the NIST QC1 hardware via an adapter, and the NIST CLOCK and QC2 hardware (FMC). +The main target board for the ARTIQ core device is the KC705 development board from Xilinx. It supports the NIST CLOCK and QC2 hardware (FMC). Common problems +++++++++++++++ * The SW13 switches on the board need to be set to 00001. -* When connected, QC1 and CLOCK adapters break the JTAG chain due to TDI not being connect to TDO on the FMC mezzanine. +* When connected, CLOCK adapter breaks the JTAG chain due to TDI not being connect to TDO on the FMC mezzanine. * On some boards, the JTAG USB connector is not correctly soldered. VADJ @@ -44,31 +44,6 @@ VADJ With the NIST CLOCK and QC2 adapters, for safe operation of the DDS buses (to prevent damage to the IO banks of the FPGA), the FMC VADJ rail of the KC705 should be changed to 3.3V. Plug the Texas Instruments USB-TO-GPIO PMBus adapter into the PMBus connector in the corner of the KC705 and use the Fusion Digital Power Designer software to configure (requires Windows). Write to chip number U55 (address 52), channel 4, which is the VADJ rail, to make it 3.3V instead of 2.5V. Power cycle the KC705 board to check that the startup voltage on the VADJ rail is now 3.3V. -NIST QC1 -++++++++ - -With the QC1 hardware, the TTL lines are mapped as follows: - -+--------------+------------+--------------+ -| RTIO channel | TTL line | Capability | -+==============+============+==============+ -| 0 | PMT0 | Input | -+--------------+------------+--------------+ -| 1 | PMT1 | Input | -+--------------+------------+--------------+ -| 2-16 | TTL0-14 | Output | -+--------------+------------+--------------+ -| 17 | SMA_GPIO_N | Input+Output | -+--------------+------------+--------------+ -| 18 | LED | Output | -+--------------+------------+--------------+ -| 19 | TTL15 | Clock | -+--------------+------------+--------------+ - -There are no SPI channels. - -The DDS bus is on channel 20. - NIST CLOCK ++++++++++ @@ -202,5 +177,3 @@ Interface Type 2 (SPI) and 2A (expanded SPI): +==============+========+========+========+========+ | 23 | PMOD_0 | PMOD_1 | PMOD_2 | PMOD_3 | +--------------+--------+--------+--------+--------+ - -The DDS bus is on channel 24. diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index c3090337b..ae111a7d9 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -43,8 +43,7 @@ Then prepare to create a new conda environment with the ARTIQ package and the ma choose a suitable name for the environment, for example ``artiq-main`` if you intend to track the main label or ``artiq-2016-04-01`` if you consider the environment a snapshot of ARTIQ on 2016-04-01. Choose the package containing the binaries for your hardware: - * ``artiq-pipistrello-nist_qc1`` for the `Pipistrello `_ board with the NIST adapter to SCSI cables and AD9858 DDS chips. - * ``artiq-kc705-nist_qc1`` for the `KC705 `_ board with the NIST adapter to SCSI cables and AD9858 DDS chips. + * ``artiq-pipistrello-nist_qc1`` for the `Pipistrello `_ board with the NIST adapter to SCSI cables; AD9858 DDS chips are not supported anymore. * ``artiq-kc705-nist_clock`` for the KC705 board with the NIST "clock" FMC backplane and AD9914 DDS chips. * ``artiq-kc705-nist_qc2`` for the KC705 board with the NIST QC2 FMC backplane and AD9914 DDS chips. @@ -136,7 +135,7 @@ Then, you can flash the board: * For the KC705 board (selecting the appropriate hardware peripheral):: - $ artiq_flash -t kc705 -m [nist_qc1/nist_clock/nist_qc2] + $ artiq_flash -t kc705 -m [nist_clock/nist_qc2] The SW13 switches also need to be set to 00001. diff --git a/doc/manual/installing_from_source.rst b/doc/manual/installing_from_source.rst index c25e74bdf..b2bbe37a2 100644 --- a/doc/manual/installing_from_source.rst +++ b/doc/manual/installing_from_source.rst @@ -171,7 +171,7 @@ These steps are required to generate gateware bitstream (``.bit``) files, build * For KC705:: - $ python3.5 -m artiq.gateware.targets.kc705 -H nist_qc1 # or nist_qc2 + $ python3.5 -m artiq.gateware.targets.kc705 -H nist_clock # or nist_qc2 .. note:: Add ``--toolchain ise`` if you wish to use ISE instead of Vivado. From 6aa5d9f6c6c778524f1fea459f79886201e5ea99 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 15:36:22 +0000 Subject: [PATCH 45/47] Remove last vestiges of nist_qc1. --- artiq/gateware/ad9xxx.py | 7 --- artiq/gateware/nist_qc1.py | 54 ------------------ artiq/gateware/targets/pipistrello.py | 56 ++++++++++--------- .../build.sh | 8 +-- .../meta.yaml | 4 +- doc/manual/core_device.rst | 26 +++------ doc/manual/installing.rst | 8 +-- 7 files changed, 49 insertions(+), 114 deletions(-) delete mode 100644 artiq/gateware/nist_qc1.py rename conda/{artiq-pipistrello-nist_qc1 => artiq-pipistrello-demo}/build.sh (64%) rename conda/{artiq-pipistrello-nist_qc1 => artiq-pipistrello-demo}/meta.yaml (86%) diff --git a/artiq/gateware/ad9xxx.py b/artiq/gateware/ad9xxx.py index 2c30af242..4c7ff66f7 100644 --- a/artiq/gateware/ad9xxx.py +++ b/artiq/gateware/ad9xxx.py @@ -24,13 +24,6 @@ class AD9xxx(Module): Design: All IO pads are registered. - - With QC1 adapter: - LVDS driver/receiver propagation delays are 3.6+4.5 ns max - LVDS state transition delays are 20, 15 ns max - Schmitt trigger delays are 6.4ns max - Round-trip addr A setup (> RX, RD, D to Z), RD prop, D valid (< D - valid), D prop is ~15 + 10 + 20 + 10 = 55ns """ def __init__(self, pads, read_wait_cycles=10, hiz_wait_cycles=3, diff --git a/artiq/gateware/nist_qc1.py b/artiq/gateware/nist_qc1.py deleted file mode 100644 index 986aa141f..000000000 --- a/artiq/gateware/nist_qc1.py +++ /dev/null @@ -1,54 +0,0 @@ -from migen.build.generic_platform import * - - -papilio_adapter_io = [ - ("ext_led", 0, Pins("B:7"), IOStandard("LVTTL")), - - # to feed the 125 MHz clock (preferrably from DDS SYNC_CLK) - # to the FPGA, use the xtrig pair. - # - # on papiliopro-adapter, xtrig (C:12) is connected to a GCLK - # - # on pipistrello, C:15 is the only GCLK in proximity, used as a button - # input, BTN2/PMT2 in papiliopro-adapter - # either improve the DDS box to feed 125MHz into the PMT2 pair, or: - # - # * disconnect C:15 from its periphery on the adapter board - # * bridge C:15 to the xtrig output of the transciever - # * optionally, disconnect C:12 from its periphery - ("xtrig", 0, Pins("C:12"), IOStandard("LVTTL")), - ("pmt", 0, Pins("C:13"), IOStandard("LVTTL")), - ("pmt", 1, Pins("C:14"), IOStandard("LVTTL")), - ("pmt", 2, Pins("C:15"), IOStandard("LVTTL")), # rarely equipped - - ("ttl", 0, Pins("C:11"), IOStandard("LVTTL")), - ("ttl", 1, Pins("C:10"), IOStandard("LVTTL")), - ("ttl", 2, Pins("C:9"), IOStandard("LVTTL")), - ("ttl", 3, Pins("C:8"), IOStandard("LVTTL")), - ("ttl", 4, Pins("C:7"), IOStandard("LVTTL")), - ("ttl", 5, Pins("C:6"), IOStandard("LVTTL")), - ("ttl", 6, Pins("C:5"), IOStandard("LVTTL")), - ("ttl", 7, Pins("C:4"), IOStandard("LVTTL")), - ("ttl_l_tx_en", 0, Pins("A:9"), IOStandard("LVTTL")), - - ("ttl", 8, Pins("C:3"), IOStandard("LVTTL")), - ("ttl", 9, Pins("C:2"), IOStandard("LVTTL")), - ("ttl", 10, Pins("C:1"), IOStandard("LVTTL")), - ("ttl", 11, Pins("C:0"), IOStandard("LVTTL")), - ("ttl", 12, Pins("B:4"), IOStandard("LVTTL")), - ("ttl", 13, Pins("A:11"), IOStandard("LVTTL")), - ("ttl", 14, Pins("B:5"), IOStandard("LVTTL")), - ("ttl", 15, Pins("A:10"), IOStandard("LVTTL")), - ("ttl_h_tx_en", 0, Pins("B:6"), IOStandard("LVTTL")), - - ("dds", 0, - Subsignal("a", Pins("A:5 B:10 A:6 B:9 A:7 B:8")), - Subsignal("d", Pins("A:12 B:3 A:13 B:2 A:14 B:1 A:15 B:0")), - Subsignal("sel", Pins("A:2 B:14 A:1 B:15 A:0")), - Subsignal("p", Pins("A:8 B:12")), - Subsignal("fud_n", Pins("B:11")), - Subsignal("wr_n", Pins("A:4")), - Subsignal("rd_n", Pins("B:13")), - Subsignal("rst_n", Pins("A:3")), - IOStandard("LVTTL")), -] diff --git a/artiq/gateware/targets/pipistrello.py b/artiq/gateware/targets/pipistrello.py index 52fb20046..0a110a0d7 100755 --- a/artiq/gateware/targets/pipistrello.py +++ b/artiq/gateware/targets/pipistrello.py @@ -18,7 +18,7 @@ from misoc.targets.pipistrello import (BaseSoC, soc_pipistrello_args, from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.soc import AMPSoC, build_artiq_soc -from artiq.gateware import rtio, nist_qc1 +from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_spartan6, dds, spi from artiq import __version__ as artiq_version @@ -61,14 +61,14 @@ class _RTIOCRG(Module, AutoCSR): f = Fraction(rtio_f, clk_freq) rtio_internal_clk = Signal() rtio_external_clk = Signal() - pmt2 = platform.request("pmt", 2) + ext_clk = platform.request("ext_clk") dcm_locked = Signal() rtio_clk = Signal() pll_locked = Signal() pll = Signal(3) pll_fb = Signal() self.specials += [ - Instance("IBUFG", i_I=pmt2, o_O=rtio_external_clk), + Instance("IBUFG", i_I=ext_clk, o_O=rtio_external_clk), Instance("DCM_CLKGEN", p_CLKFXDV_DIVIDE=2, p_CLKFX_DIVIDE=f.denominator, p_CLKFX_MD_MAX=float(f), p_CLKFX_MULTIPLY=f.numerator, p_CLKIN_PERIOD=1e9/clk_freq, @@ -124,7 +124,30 @@ TIMESPEC "TSfix_ise4" = FROM "GRPsys_clk" TO "GRPrtio_clk" TIG; rtio_clk=self.cd_rtio.clk) -class NIST_QC1(BaseSoC, AMPSoC): +_ttl_io = [ + ("ext_clk", 0, Pins("C:15"), IOStandard("LVTTL")), + + ("ttl", 0, Pins("B:0"), IOStandard("LVTTL")), + ("ttl", 1, Pins("B:1"), IOStandard("LVTTL")), + ("ttl", 2, Pins("B:2"), IOStandard("LVTTL")), + ("ttl", 3, Pins("B:3"), IOStandard("LVTTL")), + ("ttl", 4, Pins("B:4"), IOStandard("LVTTL")), + ("ttl", 5, Pins("B:5"), IOStandard("LVTTL")), + ("ttl", 6, Pins("B:6"), IOStandard("LVTTL")), + ("ttl", 7, Pins("B:7"), IOStandard("LVTTL")), + + ("ttl", 8, Pins("B:8"), IOStandard("LVTTL")), + ("ttl", 9, Pins("B:9"), IOStandard("LVTTL")), + ("ttl", 10, Pins("B:10"), IOStandard("LVTTL")), + ("ttl", 11, Pins("B:11"), IOStandard("LVTTL")), + ("ttl", 12, Pins("B:12"), IOStandard("LVTTL")), + ("ttl", 13, Pins("B:13"), IOStandard("LVTTL")), + ("ttl", 14, Pins("B:14"), IOStandard("LVTTL")), + ("ttl", 15, Pins("B:15"), IOStandard("LVTTL")), +] + + +class Demo(BaseSoC, AMPSoC): mem_map = { "timer_kernel": 0x10000000, # (shadow @0x90000000) "rtio": 0x20000000, # (shadow @0xa0000000) @@ -148,29 +171,16 @@ class NIST_QC1(BaseSoC, AMPSoC): platform.toolchain.ise_commands += """ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd {build_name}.pcf """ - platform.add_extension(nist_qc1.papilio_adapter_io) + platform.add_extension(_ttl_io) platform.add_extension(_pmod_spi) self.submodules.leds = gpio.GPIOOut(platform.request("user_led", 4)) - self.comb += [ - platform.request("ttl_l_tx_en").eq(1), - platform.request("ttl_h_tx_en").eq(1) - ] - self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq) self.csr_devices.append("rtio_crg") # RTIO channels rtio_channels = [] - # pmt1 can run on a 8x serdes if pmt0 is not used - for i in range(2): - phy = ttl_serdes_spartan6.Inout_4X(platform.request("pmt", i), - self.rtio_crg.rtiox4_stb) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=128, - ofifo_depth=4)) - # the last TTL is used for ClockGen for i in range(15): if i in (0, 1): @@ -185,10 +195,6 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=128)) - phy = ttl_simple.Output(platform.request("ext_led", 0)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4)) - for led_number in range(4): phy = ttl_simple.Output(platform.request("user_led", led_number)) self.submodules += phy @@ -212,7 +218,6 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd # RTIO logic self.submodules.rtio = rtio.RTIO(rtio_channels) self.register_kernel_cpu_csrdevice("rtio") - self.config["DDS_RTIO_CLK_RATIO"] = 8 >> self.rtio.fine_ts_width self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") self.submodules.rtio_analyzer = rtio.Analyzer( @@ -222,13 +227,12 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd def main(): parser = argparse.ArgumentParser( - description="ARTIQ core device builder / Pipistrello " - "+ NIST Ions QC1 hardware adapter") + description="ARTIQ core device builder / Pipistrello demo") builder_args(parser) soc_pipistrello_args(parser) args = parser.parse_args() - soc = NIST_QC1(**soc_pipistrello_argdict(args)) + soc = Demo(**soc_pipistrello_argdict(args)) build_artiq_soc(soc, builder_argdict(args)) diff --git a/conda/artiq-pipistrello-nist_qc1/build.sh b/conda/artiq-pipistrello-demo/build.sh similarity index 64% rename from conda/artiq-pipistrello-nist_qc1/build.sh rename to conda/artiq-pipistrello-demo/build.sh index 664da144b..9248667fd 100644 --- a/conda/artiq-pipistrello-nist_qc1/build.sh +++ b/conda/artiq-pipistrello-demo/build.sh @@ -3,12 +3,12 @@ BUILD_SETTINGS_FILE=$HOME/.m-labs/build_settings.sh [ -f $BUILD_SETTINGS_FILE ] && . $BUILD_SETTINGS_FILE -SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/pipistrello-nist_qc1 +SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/pipistrello-demo mkdir -p $SOC_PREFIX $PYTHON -m artiq.gateware.targets.pipistrello $MISOC_EXTRA_ISE_CMDLINE -cp misoc_nist_qc1_pipistrello/gateware/top.bit $SOC_PREFIX -cp misoc_nist_qc1_pipistrello/software/bios/bios.bin $SOC_PREFIX -cp misoc_nist_qc1_pipistrello/software/runtime/runtime.fbi $SOC_PREFIX +cp misoc_demo_pipistrello/gateware/top.bit $SOC_PREFIX +cp misoc_demo_pipistrello/software/bios/bios.bin $SOC_PREFIX +cp misoc_demo_pipistrello/software/runtime/runtime.fbi $SOC_PREFIX wget -P $SOC_PREFIX https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/master/bscan_spi_xc6slx45.bit diff --git a/conda/artiq-pipistrello-nist_qc1/meta.yaml b/conda/artiq-pipistrello-demo/meta.yaml similarity index 86% rename from conda/artiq-pipistrello-nist_qc1/meta.yaml rename to conda/artiq-pipistrello-demo/meta.yaml index 06b1bc006..d9975d733 100644 --- a/conda/artiq-pipistrello-nist_qc1/meta.yaml +++ b/conda/artiq-pipistrello-demo/meta.yaml @@ -1,5 +1,5 @@ package: - name: artiq-pipistrello-nist_qc1 + name: artiq-pipistrello-demo version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} source: @@ -24,4 +24,4 @@ requirements: about: home: http://m-labs.hk/artiq license: GPL - summary: 'Bitstream, BIOS and runtime for NIST_QC1 on the Pipistrello board' + summary: 'Bitstream, BIOS and runtime for the Pipistrello board' diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index 9f3bf48a7..541d97ae6 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -141,33 +141,25 @@ The low-cost Pipistrello FPGA board can be used as a lower-cost but slower alter .. warning:: The Pipistrello draws a high current over USB, and that current increases when the FPGA design is active. If you experience problems such as intermittent board freezes or USB errors, try connecting it to a self-powered USB hub. -When plugged to an adapter, the NIST QC1 hardware can be used. The TTL lines are mapped to RTIO channels as follows: +The TTL lines are mapped to RTIO channels as follows: +--------------+------------+--------------+ | RTIO channel | TTL line | Capability | +==============+============+==============+ -| 0 | PMT0 | Input | +| 0-14 | B0-14 | Output | +--------------+------------+--------------+ -| 1 | PMT1 | Input | +| 15 | USER_LED_1 | Output | +--------------+------------+--------------+ -| 2-16 | TTL0-14 | Output | +| 16 | USER_LED_2 | Output | +--------------+------------+--------------+ -| 17 | EXT_LED | Output | +| 17 | USER_LED_3 | Output | +--------------+------------+--------------+ -| 18 | USER_LED_1 | Output | +| 18 | USER_LED_4 | Output | +--------------+------------+--------------+ -| 19 | USER_LED_2 | Output | -+--------------+------------+--------------+ -| 20 | USER_LED_3 | Output | -+--------------+------------+--------------+ -| 21 | USER_LED_4 | Output | -+--------------+------------+--------------+ -| 22 | TTL15 | Clock | +| 19 | B15 | Clock | +--------------+------------+--------------+ -The input only limitation on channels 0 and 1 comes from the QC-DAQ adapter. When the adapter is not used (and physically unplugged from the Pipistrello board), the corresponding pins on the Pipistrello can be used as outputs. Do not configure these channels as outputs when the adapter is plugged, as this would cause electrical contention. - -The board can accept an external RTIO clock connected to PMT2. If the DDS box does not drive the PMT2 pair, use XTRIG and patch the XTRIG transceiver output on the adapter board onto C:15 disconnecting PMT2. +The board can accept an external RTIO clock connected to C15. The board has one RTIO SPI bus on the PMOD connector, compliant to PMOD Interface Type 2 (SPI) and 2A (expanded SPI): @@ -175,5 +167,5 @@ Interface Type 2 (SPI) and 2A (expanded SPI): +--------------+--------+--------+--------+--------+ | RTIO channel | CS_N | MOSI | MISO | CLK | +==============+========+========+========+========+ -| 23 | PMOD_0 | PMOD_1 | PMOD_2 | PMOD_3 | +| 16 | PMOD_0 | PMOD_1 | PMOD_2 | PMOD_3 | +--------------+--------+--------+--------+--------+ diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index ae111a7d9..3d9761944 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -43,13 +43,13 @@ Then prepare to create a new conda environment with the ARTIQ package and the ma choose a suitable name for the environment, for example ``artiq-main`` if you intend to track the main label or ``artiq-2016-04-01`` if you consider the environment a snapshot of ARTIQ on 2016-04-01. Choose the package containing the binaries for your hardware: - * ``artiq-pipistrello-nist_qc1`` for the `Pipistrello `_ board with the NIST adapter to SCSI cables; AD9858 DDS chips are not supported anymore. + * ``artiq-pipistrello-demo`` for the `Pipistrello `_ board. * ``artiq-kc705-nist_clock`` for the KC705 board with the NIST "clock" FMC backplane and AD9914 DDS chips. * ``artiq-kc705-nist_qc2`` for the KC705 board with the NIST QC2 FMC backplane and AD9914 DDS chips. Conda will create the environment, automatically resolve, download, and install the necessary dependencies and install the packages you select:: - $ conda create -n artiq-main artiq-pipistrello-nist_qc1 + $ conda create -n artiq-main artiq-pipistrello-demo After the installation, activate the newly created environment by name. On Unix:: @@ -79,7 +79,7 @@ When upgrading ARTIQ or when testing different versions it is recommended that n Keep previous environments around until you are certain that they are not needed anymore and a new environment is known to work correctly. You can create a new conda environment specifically to test a certain version of ARTIQ:: - $ conda create -n artiq-test-1.0rc2 artiq-pipistrello-nist_qc1=1.0rc2 + $ conda create -n artiq-test-1.0rc2 artiq-pipistrello-demo=1.0rc2 Switching between conda environments using ``$ source deactivate artiq-1.0rc2`` and ``$ source activate artiq-1.0rc1`` is the recommended way to roll back to previous versions of ARTIQ. You can list the environments you have created using:: @@ -131,7 +131,7 @@ Then, you can flash the board: * For the Pipistrello board:: - $ artiq_flash -t pipistrello -m nist_qc1 + $ artiq_flash -t pipistrello -m demo * For the KC705 board (selecting the appropriate hardware peripheral):: From 93c310dfa5ea1718bef7a6e860cdbaff42ec8c15 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Nov 2016 23:43:41 +0800 Subject: [PATCH 46/47] pipistrello: add some inputs --- artiq/gateware/targets/pipistrello.py | 6 +++--- doc/manual/core_device.rst | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/pipistrello.py b/artiq/gateware/targets/pipistrello.py index 0a110a0d7..42dc87dac 100755 --- a/artiq/gateware/targets/pipistrello.py +++ b/artiq/gateware/targets/pipistrello.py @@ -184,9 +184,9 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd # the last TTL is used for ClockGen for i in range(15): if i in (0, 1): - phy = ttl_serdes_spartan6.Output_4X(platform.request("ttl", i), - self.rtio_crg.rtiox4_stb) - elif i in (2,): # ttl2 can run on a 8x serdes if xtrig is not used + phy = ttl_serdes_spartan6.Inout_4X(platform.request("ttl", i), + self.rtio_crg.rtiox4_stb) + elif i in (2,): phy = ttl_serdes_spartan6.Output_8X(platform.request("ttl", i), self.rtio_crg.rtiox8_stb) else: diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index 541d97ae6..e70b30f11 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -146,7 +146,9 @@ The TTL lines are mapped to RTIO channels as follows: +--------------+------------+--------------+ | RTIO channel | TTL line | Capability | +==============+============+==============+ -| 0-14 | B0-14 | Output | +| 0-1 | B0-1 | Input+Output | ++--------------+------------+--------------+ +| 2-14 | B2-14 | Output | +--------------+------------+--------------+ | 15 | USER_LED_1 | Output | +--------------+------------+--------------+ From ef971ef8ba3d638eeef6c3d835af275403a44b5b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Nov 2016 23:51:39 +0800 Subject: [PATCH 47/47] RELEASE_NOTES: update --- RELEASE_NOTES.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 16bda10f0..635bb607d 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -16,6 +16,12 @@ Release notes * Datasets requested by experiments are by default archived into their HDF5 output. If this behavior is undesirable, turn it off by passing ``archive=False`` to ``get_dataset``. +* ``seconds_to_mu`` and ``mu_to_seconds`` have become methods of the core + device driver (use e.g. ``self.core.seconds_to_mu()``). +* AD9858 DDSes and NIST QC1 hardware are no longer supported. +* The Pipistrello port now has exclusively TTLs. +* The DDS class names and setup options have changed, this requires an update of + the device database. 2.0