diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 390665643..c743f2005 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -24,6 +24,10 @@ Highlights: - HVAMP_8CH 8 channel HV amplifier for Fastino / Zotino * ``artiq_ddb_template`` generates edge-counter keys that start with the key of the corresponding TTL device (e.g. ``"ttl_0_counter"`` for the edge counter on TTL device``"ttl_0"``) +* ``artiq_master`` now has an ``--experiment-subdir`` option to scan only a subdirectory of the + repository when building the list of experiments. +* The configuration entry ``rtio_clock`` supports multiple clocking settings, deprecating the usage + of compile-time options. Breaking changes: diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index 26051e2a9..ede875863 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -3,7 +3,7 @@ streaming DAC. """ from numpy import int32 -from artiq.language.core import kernel, portable, delay +from artiq.language.core import kernel, portable, delay, delay_mu from artiq.coredevice.rtio import (rtio_output, rtio_output_wide, rtio_input_data) from artiq.language.units import us @@ -191,3 +191,82 @@ class Fastino: green LED. """ self.write(0x23, leds) + + @kernel + def set_continuous(self, channel_mask): + """Enable continuous DAC updates on channels regardless of new data + being submitted. + """ + self.write(0x25, channel_mask) + + @kernel + def stage_cic_mu(self, rate_mantissa, rate_exponent, gain_exponent): + """Stage machine unit CIC interpolator configuration. + """ + if rate_mantissa < 0 or rate_mantissa >= 1 << 6: + raise ValueError("rate_mantissa out of bounds") + if rate_exponent < 0 or rate_exponent >= 1 << 4: + raise ValueError("rate_exponent out of bounds") + if gain_exponent < 0 or gain_exponent >= 1 << 6: + raise ValueError("gain_exponent out of bounds") + config = rate_mantissa | (rate_exponent << 6) | (gain_exponent << 10) + self.write(0x26, config) + + @kernel + def stage_cic(self, rate) -> TInt32: + """Compute and stage interpolator configuration. + + This method approximates the desired interpolation rate using a 10 bit + floating point representation (6 bit mantissa, 4 bit exponent) and + then determines an optimal interpolation gain compensation exponent + to avoid clipping. Gains for rates that are powers of two are accurately + compensated. Other rates lead to overall less than unity gain (but more + than 0.5 gain). + + The overall gain including gain compensation is + `actual_rate**order/2**ceil(log2(actual_rate**order))` + where `order = 3`. + + Returns the actual interpolation rate. + """ + if rate <= 0 or rate > 1 << 16: + raise ValueError("rate out of bounds") + rate_mantissa = rate + rate_exponent = 0 + while rate_mantissa > 1 << 6: + rate_exponent += 1 + rate_mantissa >>= 1 + order = 3 + gain = 1 + for i in range(order): + gain *= rate_mantissa + gain_exponent = 0 + while gain > 1 << gain_exponent: + gain_exponent += 1 + gain_exponent += order*rate_exponent + assert gain_exponent <= order*16 + self.stage_cic_mu(rate_mantissa - 1, rate_exponent, gain_exponent) + return rate_mantissa << rate_exponent + + @kernel + def apply_cic(self, channel_mask): + """Apply the staged interpolator configuration on the specified channels. + + Each Fastino channel includes a fourth order (cubic) CIC interpolator with + variable rate change and variable output gain compensation (see + :meth:`stage_cic`). + + Channels using non-unity interpolation rate should have + continous DAC updates enabled (see :meth:`set_continuous`) unless + their output is supposed to be constant. + + This method resets and settles the affected interpolators. There will be + no output updates for the next `order = 3` input samples. + Affected channels will only accept one input sample per input sample + period. This method synchronizes the input sample period to the current + frame on the affected channels. + + If application of new interpolator settings results in a change of the + overall gain, there will be a corresponding output step. + """ + self.write(0x27, channel_mask) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index daaed659d..5f7cd7108 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -203,6 +203,7 @@ class Phaser: self.measure_frame_timestamp() if self.frame_tstamp < 0: raise ValueError("frame timestamp measurement timed out") + delay(.1*ms) # reset self.set_cfg(dac_resetb=0, dac_sleep=1, dac_txena=0, diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 194952672..77d262538 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "fringe" version = "1.2.1" -source = "git+https://git.m-labs.hk/M-Labs/libfringe.git?rev=9748bb#9748bb8af86c131d45be1238ea4d5f965a974630" +source = "git+https://git.m-labs.hk/M-Labs/libfringe.git?rev=3ecbe5#3ecbe53f7644b18ee46ebd5b2ca12c9cbceec43a" dependencies = [ "libc 0.2.101", ] diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 1ef7426a1..9a41bdb4b 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -17,7 +17,7 @@ use board_misoc::slave_fpga; #[cfg(has_ethmac)] use board_misoc::{clock, ethmac, net_settings}; use board_misoc::uart_console::Console; -use riscv::register::{mcause, mepc}; +use riscv::register::{mcause, mepc, mtval}; fn check_integrity() -> bool { extern { @@ -522,7 +522,8 @@ pub extern fn main() -> i32 { pub extern fn exception(_regs: *const u32) { let pc = mepc::read(); let cause = mcause::read().cause(); - panic!("{:?} at PC {:#08x}", cause, u32::try_from(pc).unwrap()) + let mtval = mtval::read(); + panic!("{:?} at PC {:#08x}, trap value {:#08x}", cause, u32::try_from(pc).unwrap(), mtval); } #[no_mangle] diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index aaedbd018..d915d7e81 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -23,7 +23,7 @@ use proto_artiq::{kernel_proto, rpc_proto}; use kernel_proto::*; #[cfg(has_rtio_dma)] use board_misoc::csr; -use riscv::register::{mcause, mepc}; +use riscv::register::{mcause, mepc, mtval}; fn send(request: &Message) { unsafe { mailbox::send(request as *const _ as usize) } @@ -493,11 +493,13 @@ pub unsafe fn main() { let _end = library.lookup(b"_end").unwrap(); let __modinit__ = library.lookup(b"__modinit__").unwrap(); let typeinfo = library.lookup(b"typeinfo"); + let _sstack_guard = library.lookup(b"_sstack_guard").unwrap(); LIBRARY = Some(library); ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize); + board_misoc::pmp::init_stack_guard(_sstack_guard as usize); board_misoc::cache::flush_cpu_dcache(); board_misoc::cache::flush_cpu_icache(); @@ -530,7 +532,8 @@ pub unsafe fn main() { pub extern fn exception(_regs: *const u32) { let pc = mepc::read(); let cause = mcause::read().cause(); - panic!("{:?} at PC {:#08x}", cause, u32::try_from(pc).unwrap()) + let mtval = mtval::read(); + panic!("{:?} at PC {:#08x}, trap value {:#08x}", cause, u32::try_from(pc).unwrap(), mtval); } #[no_mangle] diff --git a/artiq/firmware/libboard_misoc/riscv32ima/boot.rs b/artiq/firmware/libboard_misoc/riscv32ima/boot.rs index 32e9cfbc3..0d2254da1 100644 --- a/artiq/firmware/libboard_misoc/riscv32ima/boot.rs +++ b/artiq/firmware/libboard_misoc/riscv32ima/boot.rs @@ -1,4 +1,5 @@ -use super::cache; +use super::{cache, pmp}; +use riscv::register::*; pub unsafe fn reset() -> ! { llvm_asm!(r#" @@ -16,3 +17,14 @@ pub unsafe fn jump(addr: usize) -> ! { "# : : "r"(addr) : : "volatile"); loop {} } + +pub unsafe fn start_user(addr: usize) -> ! { + pmp::enable_user_memory(); + mstatus::set_mpp(mstatus::MPP::User); + mepc::write(addr); + llvm_asm!( + "mret" + : : : : "volatile" + ); + unreachable!() +} diff --git a/artiq/firmware/libboard_misoc/riscv32ima/mod.rs b/artiq/firmware/libboard_misoc/riscv32ima/mod.rs index 217ef713f..a8f498adc 100644 --- a/artiq/firmware/libboard_misoc/riscv32ima/mod.rs +++ b/artiq/firmware/libboard_misoc/riscv32ima/mod.rs @@ -1,2 +1,3 @@ pub mod cache; pub mod boot; +pub mod pmp; diff --git a/artiq/firmware/libboard_misoc/riscv32ima/pmp.rs b/artiq/firmware/libboard_misoc/riscv32ima/pmp.rs new file mode 100644 index 000000000..9ac80b9e3 --- /dev/null +++ b/artiq/firmware/libboard_misoc/riscv32ima/pmp.rs @@ -0,0 +1,55 @@ +use riscv::register::{pmpaddr0, pmpaddr1, pmpaddr2, pmpaddr3, pmpcfg0}; + +static mut THREAD_DEPTH: u8 = 0; + +const PMP_L : usize = 0b10000000; +const PMP_NAPOT: usize = 0b00011000; +const PMP_X : usize = 0b00000100; +const PMP_W : usize = 0b00000010; +const PMP_R : usize = 0b00000001; +const PMP_OFF : usize = 0b00000000; + +#[inline(always)] +pub unsafe fn init_stack_guard(guard_base: usize) { + pmpaddr2::write((guard_base >> 2) | ((0x1000 - 1) >> 3)); + pmpcfg0::write((PMP_L | PMP_NAPOT) << 16); +} + +#[inline(always)] +pub fn enable_user_memory() { + pmpaddr3::write((0x80000000 - 1) >> 3); + pmpcfg0::write((PMP_L | PMP_NAPOT | PMP_X | PMP_W | PMP_R) << 24); +} + +#[inline(always)] +pub unsafe fn push_pmp_region(addr: usize) { + let pmp_addr = (addr >> 2) | ((0x1000 - 1) >> 3); + match THREAD_DEPTH { + // Activate PMP0 when switching from main stack to thread + 0 => { + pmpaddr0::write(pmp_addr); + pmpcfg0::write(PMP_NAPOT); + } + + // Temporarily activate PMP1 when spawning a thread from a thread + // The thread should swap back to the main stack very soon after init + 1 => { + pmpaddr1::write(pmp_addr); + pmpcfg0::write(PMP_NAPOT << 8 | PMP_NAPOT); + } + + // Thread *running* another thread should not be possible + _ => unreachable!() + } + THREAD_DEPTH += 1; +} + +#[inline(always)] +pub unsafe fn pop_pmp_region() { + THREAD_DEPTH -= 1; + match THREAD_DEPTH { + 0 => pmpcfg0::write(PMP_OFF), + 1 => pmpcfg0::write(PMP_NAPOT), + _ => unreachable!() + } +} diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index a29acbb86..ee987ad2d 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -32,6 +32,6 @@ riscv = { version = "0.6.0", features = ["inline-asm"] } [dependencies.fringe] git = "https://git.m-labs.hk/M-Labs/libfringe.git" -rev = "9748bb" +rev = "3ecbe5" default-features = false features = ["alloc"] diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index c04ec3a05..45fb76f91 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -29,7 +29,7 @@ use core::cell::RefCell; use core::convert::TryFrom; use smoltcp::wire::IpCidr; -use board_misoc::{csr, ident, clock, spiflash, config, net_settings}; +use board_misoc::{csr, ident, clock, spiflash, config, net_settings, pmp, boot}; #[cfg(has_ethmac)] use board_misoc::ethmac; #[cfg(has_drtio)] @@ -40,7 +40,7 @@ use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_pro #[cfg(has_rtio_analyzer)] use proto_artiq::analyzer_proto; -use riscv::register::{mcause, mepc}; +use riscv::register::{mcause, mepc, mtval}; mod rtio_clocking; mod rtio_mgt; @@ -247,10 +247,15 @@ pub extern fn main() -> i32 { extern { static mut _fheap: u8; static mut _eheap: u8; + static mut _sstack_guard: u8; } ALLOC.add_range(&mut _fheap, &mut _eheap); - logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(startup); + pmp::init_stack_guard(&_sstack_guard as *const u8 as usize); + + logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(|| + boot::start_user(startup as usize) + ); 0 } @@ -285,6 +290,18 @@ pub extern fn exception(regs: *const TrapFrame) { mcause::Trap::Interrupt(source) => { info!("Called interrupt with {:?}", source); }, + + mcause::Trap::Exception(mcause::Exception::UserEnvCall) => { + unsafe { + if (*regs).a7 == 0 { + pmp::pop_pmp_region() + } else { + pmp::push_pmp_region((*regs).a7) + } + } + mepc::write(pc + 4); + }, + mcause::Trap::Exception(e) => { println!("Trap frame: {:x?}", unsafe { *regs }); @@ -302,7 +319,8 @@ pub extern fn exception(regs: *const TrapFrame) { } hexdump(u32::try_from(pc).unwrap()); - panic!("exception {:?} at PC 0x{:x}", e, u32::try_from(pc).unwrap()) + let mtval = mtval::read(); + panic!("exception {:?} at PC 0x{:x}, trap value 0x{:x}", e, u32::try_from(pc).unwrap(), mtval) } } } diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index b6cf5f395..f0330b4d9 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -4,29 +4,66 @@ use board_artiq::si5324; #[cfg(has_drtio)] use board_misoc::{csr, clock}; -#[derive(Debug)] +#[derive(Debug, PartialEq)] +#[allow(non_camel_case_types)] pub enum RtioClock { - Internal = 0, - External = 1 + Default, + Int_125, + Int_100, + Int_150, + Ext0_Bypass, + Ext0_Synth0_10to125, + Ext0_Synth0_100to125, + Ext0_Synth0_125to125, } +#[allow(unreachable_code)] fn get_rtio_clock_cfg() -> RtioClock { - config::read("rtio_clock", |result| { - match result { - Ok(b"i") => { - info!("using internal RTIO clock"); - RtioClock::Internal + config::read_str("rtio_clock", |result| { + let res = match result { + Ok("int_125") => RtioClock::Int_125, + Ok("int_100") => RtioClock::Int_100, + Ok("int_150") => RtioClock::Int_150, + Ok("ext0_bypass") => RtioClock::Ext0_Bypass, + Ok("ext0_bypass_125") => RtioClock::Ext0_Bypass, + Ok("ext0_bypass_100") => RtioClock::Ext0_Bypass, + Ok("ext0_synth0_10to125") => RtioClock::Ext0_Synth0_10to125, + Ok("ext0_synth0_100to125") => RtioClock::Ext0_Synth0_100to125, + Ok("ext0_synth0_125to125") => RtioClock::Ext0_Synth0_125to125, + Ok("i") => { + warn!("Using legacy rtio_clock setting ('i'). Falling back to default. This will be deprecated."); + RtioClock::Default }, - Ok(b"e") => { - info!("using external RTIO clock"); - RtioClock::External + Ok("e") => { + warn!("Using legacy rtio_clock setting ('e'). This will be deprecated."); + RtioClock::Ext0_Bypass }, _ => { - info!("using internal RTIO clock (by default)"); - RtioClock::Internal - }, + warn!("rtio_clock setting not recognised. Falling back to default."); + RtioClock::Default + } + }; + if res == RtioClock::Default { + #[cfg(any(si5324_ext_ref, ext_ref_frequency))] + warn!("si5324_ext_ref and ext_ref_frequency compile-time options are deprecated. Please use the rtio_clock coreconfig settings instead."); + #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "10.0"))] + return RtioClock::Ext0_Synth0_10to125; + #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "100.0"))] + return RtioClock::Ext0_Synth0_100to125; + #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "125.0"))] + return RtioClock::Ext0_Synth0_125to125; + #[cfg(all(rtio_frequency = "125.0", not(si5324_ext_ref)))] + return RtioClock::Int_125; + #[cfg(all(rtio_frequency = "150.0", not(si5324_ext_ref)))] + return RtioClock::Int_150; + #[cfg(all(rtio_frequency = "100.0", not(si5324_ext_ref)))] + return RtioClock::Int_100; + //in case nothing is set + return RtioClock::Int_125; } - }) + res + }) + } #[cfg(has_rtio_crg)] @@ -41,9 +78,23 @@ pub mod crg { #[cfg(has_rtio_clock_switch)] pub fn init(clk: RtioClock) -> bool { + let clk_sel: u8 = match clk { + RtioClock::Ext0_Bypass => { + info!("Using external clock"); + 1 + }, + RtioClock::Int_125 => { + info!("Using internal RTIO clock"); + 0 + }, + _ => { + warn!("rtio_clock setting '{:?}' is not supported. Using default internal RTIO clock instead", clk); + 0 + } + }; unsafe { csr::rtio_crg::pll_reset_write(1); - csr::rtio_crg::clock_sel_write(clk as u8); + csr::rtio_crg::clock_sel_write(clk_sel); csr::rtio_crg::pll_reset_write(0); } clock::spin_us(150); @@ -52,6 +103,7 @@ pub mod crg { #[cfg(not(has_rtio_clock_switch))] pub fn init() -> bool { + info!("Using internal RTIO clock"); unsafe { csr::rtio_crg::pll_reset_write(0); } @@ -66,84 +118,99 @@ pub mod crg { } #[cfg(si5324_as_synthesizer)] -fn setup_si5324_as_synthesizer() { - // 125 MHz output from 10 MHz CLKINx reference, 504 Hz BW - #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "10.0"))] - const SI5324_SETTINGS: si5324::FrequencySettings - = si5324::FrequencySettings { - n1_hs : 10, - nc1_ls : 4, - n2_hs : 10, - n2_ls : 300, - n31 : 6, - n32 : 6, - bwsel : 4, - crystal_ref: false - }; - // 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth - #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "100.0"))] - const SI5324_SETTINGS: si5324::FrequencySettings - = si5324::FrequencySettings { - n1_hs : 10, - nc1_ls : 4, - n2_hs : 10, - n2_ls : 260, - n31 : 52, - n32 : 52, - bwsel : 4, - crystal_ref: false - }; - // 125MHz output, from 125MHz CLKINx reference, 606 Hz loop bandwidth - #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "125.0"))] - const SI5324_SETTINGS: si5324::FrequencySettings - = si5324::FrequencySettings { - n1_hs : 5, - nc1_ls : 8, - n2_hs : 7, - n2_ls : 360, - n31 : 63, - n32 : 63, - bwsel : 4, - crystal_ref: false - }; - // 125MHz output, from crystal, 7 Hz - #[cfg(all(rtio_frequency = "125.0", not(si5324_ext_ref)))] - const SI5324_SETTINGS: si5324::FrequencySettings - = si5324::FrequencySettings { - n1_hs : 10, - nc1_ls : 4, - n2_hs : 10, - n2_ls : 19972, - n31 : 4565, - n32 : 4565, - bwsel : 4, - crystal_ref: true - }; - // 150MHz output, from crystal - #[cfg(all(rtio_frequency = "150.0", not(si5324_ext_ref)))] - const SI5324_SETTINGS: si5324::FrequencySettings - = si5324::FrequencySettings { - n1_hs : 9, - nc1_ls : 4, - n2_hs : 10, - n2_ls : 33732, - n31 : 7139, - n32 : 7139, - bwsel : 3, - crystal_ref: true - }; - // 100MHz output, from crystal. Also used as reference for Sayma HMC830. - #[cfg(all(rtio_frequency = "100.0", not(si5324_ext_ref)))] - const SI5324_SETTINGS: si5324::FrequencySettings - = si5324::FrequencySettings { - n1_hs : 9, - nc1_ls : 6, - n2_hs : 10, - n2_ls : 33732, - n31 : 7139, - n32 : 7139, - bwsel : 3, - crystal_ref: true +fn setup_si5324_as_synthesizer(cfg: RtioClock) { + let si5324_settings = match cfg { + RtioClock::Ext0_Synth0_10to125 => { // 125 MHz output from 10 MHz CLKINx reference, 504 Hz BW + info!("using 10MHz reference to make 125MHz RTIO clock with PLL"); + si5324::FrequencySettings { + n1_hs : 10, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 300, + n31 : 6, + n32 : 6, + bwsel : 4, + crystal_ref: false + } + }, + RtioClock::Ext0_Synth0_100to125 => { // 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth + info!("using 10MHz reference to make 125MHz RTIO clock with PLL"); + si5324::FrequencySettings { + n1_hs : 10, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 260, + n31 : 52, + n32 : 52, + bwsel : 4, + crystal_ref: false + } + }, + RtioClock::Ext0_Synth0_125to125 => { // 125MHz output, from 125MHz CLKINx reference, 606 Hz loop bandwidth + info!("using 10MHz reference to make 125MHz RTIO clock with PLL"); + si5324::FrequencySettings { + n1_hs : 5, + nc1_ls : 8, + n2_hs : 7, + n2_ls : 360, + n31 : 63, + n32 : 63, + bwsel : 4, + crystal_ref: false + } + }, + RtioClock::Int_150 => { // 150MHz output, from crystal + info!("using internal 150MHz RTIO clock"); + si5324::FrequencySettings { + n1_hs : 9, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 33732, + n31 : 7139, + n32 : 7139, + bwsel : 3, + crystal_ref: true + } + }, + RtioClock::Int_100 => { // 100MHz output, from crystal. Also used as reference for Sayma HMC830. + info!("using internal 100MHz RTIO clock"); + si5324::FrequencySettings { + n1_hs : 9, + nc1_ls : 6, + n2_hs : 10, + n2_ls : 33732, + n31 : 7139, + n32 : 7139, + bwsel : 3, + crystal_ref: true + } + }, + RtioClock::Int_125 => { // 125MHz output, from crystal, 7 Hz + info!("using internal 125MHz RTIO clock"); + si5324::FrequencySettings { + n1_hs : 10, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 19972, + n31 : 4565, + n32 : 4565, + bwsel : 4, + crystal_ref: true + } + } + _ => { // 125MHz output like above, default (if chosen option is not supported) + warn!("rtio_clock setting '{:?}' is not supported. Falling back to default internal 125MHz RTIO clock.", cfg); + si5324::FrequencySettings { + n1_hs : 10, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 19972, + n31 : 4565, + n32 : 4565, + bwsel : 4, + crystal_ref: true + } + } }; #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0", not(si5324_ext_ref)))] let si5324_ref_input = si5324::Input::Ckin2; @@ -155,10 +222,11 @@ fn setup_si5324_as_synthesizer() { let si5324_ref_input = si5324::Input::Ckin2; #[cfg(soc_platform = "kc705")] let si5324_ref_input = si5324::Input::Ckin2; - si5324::setup(&SI5324_SETTINGS, si5324_ref_input).expect("cannot initialize Si5324"); + si5324::setup(&si5324_settings, si5324_ref_input).expect("cannot initialize Si5324"); } pub fn init() { + let clock_cfg = get_rtio_clock_cfg(); #[cfg(si5324_as_synthesizer)] { #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] @@ -169,9 +237,12 @@ pub fn init() { let si5324_ext_input = si5324::Input::Ckin2; #[cfg(soc_platform = "kc705")] let si5324_ext_input = si5324::Input::Ckin2; - match get_rtio_clock_cfg() { - RtioClock::Internal => setup_si5324_as_synthesizer(), - RtioClock::External => si5324::bypass(si5324_ext_input).expect("cannot bypass Si5324") + match clock_cfg { + RtioClock::Ext0_Bypass => { + info!("using external RTIO clock with PLL bypass"); + si5324::bypass(si5324_ext_input).expect("cannot bypass Si5324") + }, + _ => setup_si5324_as_synthesizer(clock_cfg), } } @@ -189,7 +260,7 @@ pub fn init() { #[cfg(has_rtio_crg)] { #[cfg(has_rtio_clock_switch)] - let result = crg::init(get_rtio_clock_cfg()); + let result = crg::init(clock_cfg); #[cfg(not(has_rtio_clock_switch))] let result = crg::init(); if !result { diff --git a/artiq/firmware/runtime/runtime.ld b/artiq/firmware/runtime/runtime.ld index 81138fea3..9f60bf3ac 100644 --- a/artiq/firmware/runtime/runtime.ld +++ b/artiq/firmware/runtime/runtime.ld @@ -69,8 +69,11 @@ SECTIONS _ebss = .; } > runtime - .stack (NOLOAD) : ALIGN(16) + .stack (NOLOAD) : ALIGN(0x1000) { + _sstack_guard = .; + . += 0x1000; + _estack = .; . += 0x10000; _fstack = . - 16; } > runtime diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index 7b182a3e4..d6a347269 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -61,7 +61,8 @@ impl Thread { let spawned = io.spawned.clone(); let sockets = io.sockets.clone(); - let stack = OwnedStack::new(stack_size); + // Add a 4k stack guard to the stack of any new threads + let stack = OwnedStack::new(stack_size + 4096); ThreadHandle::new(Thread { generator: Generator::unsafe_new(stack, |yielder, _| { f(Io { diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index f9e3d9e7c..e0ec83612 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -9,7 +9,7 @@ extern crate board_artiq; extern crate riscv; use core::convert::TryFrom; -use board_misoc::{csr, ident, clock, uart_logger, i2c}; +use board_misoc::{csr, ident, clock, uart_logger, i2c, pmp}; #[cfg(has_si5324)] use board_artiq::si5324; #[cfg(has_wrpll)] @@ -18,7 +18,7 @@ use board_artiq::{spi, drtioaux}; use board_artiq::drtio_routing; #[cfg(has_hmc830_7043)] use board_artiq::hmc830_7043; -use riscv::register::{mcause, mepc}; +use riscv::register::{mcause, mepc, mtval}; mod repeater; #[cfg(has_jdcg)] @@ -449,6 +449,14 @@ const SI5324_SETTINGS: si5324::FrequencySettings #[no_mangle] pub extern fn main() -> i32 { + extern { + static mut _sstack_guard: u8; + } + + unsafe { + pmp::init_stack_guard(&_sstack_guard as *const u8 as usize); + } + clock::init(); uart_logger::ConsoleLogger::register(); @@ -662,7 +670,8 @@ pub extern fn exception(_regs: *const u32) { } hexdump(u32::try_from(pc).unwrap()); - panic!("exception {:?} at PC 0x{:x}", cause, u32::try_from(pc).unwrap()) + let mtval = mtval::read(); + panic!("exception {:?} at PC 0x{:x}, trap value 0x{:x}", cause, u32::try_from(pc).unwrap(), mtval) } #[no_mangle] diff --git a/artiq/firmware/satman/satman.ld b/artiq/firmware/satman/satman.ld index bf7ef51d0..37de797c2 100644 --- a/artiq/firmware/satman/satman.ld +++ b/artiq/firmware/satman/satman.ld @@ -58,8 +58,10 @@ SECTIONS _ebss = .; } > main_ram - .stack (NOLOAD) : ALIGN(16) + .stack (NOLOAD) : ALIGN(0x1000) { + _sstack_guard = .; + . += 0x1000; _estack = .; . += 0x10000; _fstack = . - 16; diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index d7a5bdb78..1641e31fd 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -418,8 +418,8 @@ def main(): magic = 0x5352544d # "SRTM", see sayma_rtm target length = bin_file.tell() - 8 bin_file.seek(0) - bin_file.write(magic.to_bytes(4, byteorder="big")) - bin_file.write(length.to_bytes(4, byteorder="big")) + bin_file.write(magic.to_bytes(4, byteorder="little")) + bin_file.write(length.to_bytes(4, byteorder="little")) atexit.register(lambda: os.unlink(bin_filename)) return bin_filename diff --git a/artiq/frontend/artiq_master.py b/artiq/frontend/artiq_master.py index 1a5073692..ef46fb9bb 100755 --- a/artiq/frontend/artiq_master.py +++ b/artiq/frontend/artiq_master.py @@ -50,6 +50,10 @@ def get_argparser(): group.add_argument( "-r", "--repository", default="repository", help="path to the repository (default: '%(default)s')") + group.add_argument( + "--experiment-subdir", default="", + help=("path to the experiment folder from the repository root " + "(default: '%(default)s')")) log_args(parser) @@ -104,7 +108,8 @@ def main(): repo_backend = GitBackend(args.repository) else: repo_backend = FilesystemBackend(args.repository) - experiment_db = ExperimentDB(repo_backend, worker_handlers) + experiment_db = ExperimentDB( + repo_backend, worker_handlers, args.experiment_subdir) atexit.register(experiment_db.close) scheduler = Scheduler(RIDCounter(), worker_handlers, experiment_db) diff --git a/artiq/gateware/rtio/phy/fastino.py b/artiq/gateware/rtio/phy/fastino.py index ba8a7b5c9..474bab0f3 100644 --- a/artiq/gateware/rtio/phy/fastino.py +++ b/artiq/gateware/rtio/phy/fastino.py @@ -27,16 +27,16 @@ class Fastino(Module): # dac data words dacs = [Signal(16) for i in range(32)] + header = Record([ ("cfg", 4), ("leds", 8), - ("reserved", 8), + ("typ", 1), + ("reserved", 7), ("addr", 4), ("enable", len(dacs)), ]) - body = Cat(header.raw_bits(), dacs) - assert len(body) == len(self.serializer.payload) - self.comb += self.serializer.payload.eq(body) + assert len(Cat(header.raw_bits(), dacs)) == len(self.serializer.payload) # # # @@ -62,38 +62,61 @@ class Fastino(Module): # address space is sparse. hold = Signal.like(header.enable) + continuous = Signal.like(header.enable) + cic_config = Signal(16) read_regs = Array([Signal.like(self.serializer.readback) for _ in range(1 << len(header.addr))]) cases = { # update - 0x20: header.enable.eq(header.enable | self.rtlink.o.data), + 0x20: [ + header.enable.eq(self.rtlink.o.data), + header.typ.eq(0), + ], # hold 0x21: hold.eq(self.rtlink.o.data), # cfg 0x22: header.cfg.eq(self.rtlink.o.data), # leds 0x23: header.leds.eq(self.rtlink.o.data), - # reserved + # reserved bits 0x24: header.reserved.eq(self.rtlink.o.data), + # force continuous DAC updates + 0x25: continuous.eq(self.rtlink.o.data), + # interpolator configuration stage + 0x26: cic_config.eq(self.rtlink.o.data), + # interpolator update flags + 0x27: [ + header.enable.eq(self.rtlink.o.data), + header.typ.eq(1), + ], } for i in range(0, len(dacs), width): cases[i] = [ Cat(dacs[i:i + width]).eq(self.rtlink.o.data), - [If(~hold[i + j], + [If(~hold[i + j] & (header.typ == 0), header.enable[i + j].eq(1), ) for j in range(width)] ] + self.comb += [ + If(header.typ == 0, + self.serializer.payload.eq(Cat(header.raw_bits(), dacs)), + ).Else( + self.serializer.payload.eq(Cat(header.raw_bits(), Replicate(cic_config, len(dacs)))), + ), + ] + self.sync.rio_phy += [ If(self.serializer.stb, - header.enable.eq(0), + header.typ.eq(0), + header.enable.eq(continuous), read_regs[header.addr].eq(self.serializer.readback), header.addr.eq(header.addr + 1), ), - If(self.rtlink.o.stb & ~self.rtlink.o.address[-1], - Case(self.rtlink.o.address[:-1], cases), + If(self.rtlink.o.stb, + Case(self.rtlink.o.address, cases), ), ] diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index b4401e9e0..7fa740381 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -240,7 +240,7 @@ class SatmanSoCBuilder(Builder): "satman.bin") with open(satman, "rb") as boot_file: boot_data = [] - unpack_endian = ">I" + unpack_endian = "