diff --git a/src/Cargo.lock b/src/Cargo.lock index a96535a9..2a908988 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -390,6 +390,7 @@ dependencies = [ "cslice", "dwarf", "dyld", + "embedded-hal", "fatfs", "futures", "libasync", @@ -399,6 +400,7 @@ dependencies = [ "libregister", "libsupport_zynq", "log", + "nb", "num-derive", "num-traits", "unwind", diff --git a/src/runtime/Cargo.toml b/src/runtime/Cargo.toml index 96f45983..56f08e53 100644 --- a/src/runtime/Cargo.toml +++ b/src/runtime/Cargo.toml @@ -14,18 +14,22 @@ num-traits = { version = "0.2", default-features = false } num-derive = "0.3" cslice = "0.3" log = "0.4" +nb = "0.1" +embedded-hal = "0.2" core_io = { version = "0.1", features = ["collections"] } byteorder = { version = "1.3", default-features = false } void = { version = "1", default-features = false } futures = { version = "0.3", default-features = false, features = ["async-await"] } async-recursion = "0.3" +fatfs = { version = "0.3", features = ["core_io"], default-features = false } + libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } libsupport_zynq = { default-features = false, git = "https://git.m-labs.hk/M-Labs/zc706.git" } libcortex_a9 = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } libasync = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } libregister = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } + dyld = { path = "../libdyld" } dwarf = { path = "../libdwarf" } unwind = { path = "../libunwind" } libc = { path = "../libc" } -fatfs = { version = "0.3", features = ["core_io"], default-features = false } diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index 6fe6af91..4c0c4189 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -9,9 +9,11 @@ extern crate alloc; use core::{cmp, str}; use log::{info, warn}; -use libboard_zynq::{timer::GlobalTimer, logger, devc, slcr}; +use libboard_zynq::{timer::GlobalTimer, time::Milliseconds, logger, devc, slcr}; use libsupport_zynq::ram; use libregister::RegisterW; +use nb::block; +use embedded_hal::timer::CountDown; mod sd_reader; mod config; @@ -29,28 +31,7 @@ mod load_pl; mod eh_artiq; mod panic; -fn identifier_read(buf: &mut [u8]) -> &str { - unsafe { - pl::csr::identifier::address_write(0); - let len = pl::csr::identifier::data_read(); - let len = cmp::min(len, buf.len() as u8); - for i in 0..len { - pl::csr::identifier::address_write(1 + i); - buf[i as usize] = pl::csr::identifier::data_read(); - } - str::from_utf8_unchecked(&buf[..len as usize]) - } -} - -#[no_mangle] -pub fn main_core0() { - let timer = GlobalTimer::start(); - let _ = logger::init(); - log::set_max_level(log::LevelFilter::Debug); - info!("NAR3/Zynq7000 starting..."); - - ram::init_alloc_linker(); - +fn init_gateware() { // Set up PS->PL clocks slcr::RegisterBlock::unlocked(|slcr| { // As we are touching the mux, the clock may glitch, so reset the PL. @@ -87,11 +68,73 @@ pub fn main_core0() { Err(e) => info!("Failure loading bitstream: {}", e), } } - info!("detected gateware: {}", identifier_read(&mut [0; 64])); +} + +fn identifier_read(buf: &mut [u8]) -> &str { + unsafe { + pl::csr::identifier::address_write(0); + let len = pl::csr::identifier::data_read(); + let len = cmp::min(len, buf.len() as u8); + for i in 0..len { + pl::csr::identifier::address_write(1 + i); + buf[i as usize] = pl::csr::identifier::data_read(); + } + str::from_utf8_unchecked(&buf[..len as usize]) + } +} + +fn init_rtio(timer: GlobalTimer, cfg: &config::Config) { + let clock_sel = + if let Ok(rtioclk) = cfg.read_str("rtioclk") { + match rtioclk.as_ref() { + "internal" => { + info!("using internal RTIO clock"); + 0 + }, + "external" => { + info!("using external RTIO clock"); + 1 + }, + other => { + warn!("RTIO clock specification '{}' not recognized", other); + info!("using internal RTIO clock"); + 0 + }, + } + } else { + info!("using internal RTIO clock (default)"); + 0 + }; + + unsafe { + pl::csr::rtio_crg::pll_reset_write(1); + pl::csr::rtio_crg::clock_sel_write(clock_sel); + pl::csr::rtio_crg::pll_reset_write(0); + } + let mut countdown = timer.countdown(); + countdown.start(Milliseconds(1)); + block!(countdown.wait()).unwrap(); + let locked = unsafe { pl::csr::rtio_crg::pll_locked_read() != 0 }; + if !locked { + panic!("RTIO PLL failed to lock"); + } unsafe { pl::csr::rtio_core::reset_phy_write(1); } +} + +#[no_mangle] +pub fn main_core0() { + let timer = GlobalTimer::start(); + let _ = logger::init(); + log::set_max_level(log::LevelFilter::Debug); + info!("NAR3/Zynq7000 starting..."); + + ram::init_alloc_linker(); + + init_gateware(); + info!("detected gateware: {}", identifier_read(&mut [0; 64])); let cfg = match config::Config::new() { Ok(cfg) => cfg, @@ -100,5 +143,8 @@ pub fn main_core0() { config::Config::new_dummy() } }; + + init_rtio(timer, &cfg); + comms::main(timer, &cfg); } diff --git a/src/zc706.py b/src/zc706.py index 20f70e85..3c2d9943 100755 --- a/src/zc706.py +++ b/src/zc706.py @@ -3,15 +3,61 @@ import argparse from migen import * - +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.cdc import MultiReg from migen_axi.integration.soc_core import SoCCore from migen_axi.platforms import zc706 +from misoc.interconnect.csr import * from misoc.integration import cpu_interface from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2 +class RTIOCRG(Module, AutoCSR): + def __init__(self, platform, rtio_internal_clk): + self.clock_sel = CSRStorage() + self.pll_reset = CSRStorage(reset=1) + self.pll_locked = CSRStatus() + self.clock_domains.cd_rtio = ClockDomain() + self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) + + rtio_external_clk = Signal() + user_sma_clock = platform.request("user_sma_clock") + platform.add_period_constraint(user_sma_clock.p, 8.0) + self.specials += Instance("IBUFDS", + i_I=user_sma_clock.p, i_IB=user_sma_clock.n, + o_O=rtio_external_clk) + + pll_locked = Signal() + rtio_clk = Signal() + rtiox4_clk = Signal() + self.specials += [ + Instance("PLLE2_ADV", + p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + + p_REF_JITTER1=0.01, + p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, + i_CLKIN1=rtio_internal_clk, i_CLKIN2=rtio_external_clk, + # Warning: CLKINSEL=0 means CLKIN2 is selected + i_CLKINSEL=~self.clock_sel.storage, + + # VCO @ 1GHz when using 125MHz input + p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, + i_CLKFBIN=self.cd_rtio.clk, + i_RST=self.pll_reset.storage, + + o_CLKFBOUT=rtio_clk, + + p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0, + o_CLKOUT0=rtiox4_clk), + Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk), + Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), + AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), + MultiReg(pll_locked, self.pll_locked.status) + ] + + class ZC706(SoCCore): def __init__(self): platform = zc706.Platform() @@ -22,11 +68,9 @@ class ZC706(SoCCore): platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]") platform.add_platform_command("set_input_jitter clk_fpga_0 0.24") - self.clock_domains.cd_rtio = ClockDomain() - self.comb += [ - self.cd_rtio.clk.eq(self.ps7.cd_sys.clk), - self.cd_rtio.rst.eq(self.ps7.cd_sys.rst) - ] + + self.submodules.rtio_crg = RTIOCRG(self.platform, self.ps7.cd_sys.clk) + self.csr_devices.append("rtio_crg") def add_rtio(self, rtio_channels): self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3)