make RTIO clock switch optional and simplify

Kasli no longer has an internal RTIO clock.
Switching clocks dynamically is no longer supported.
This commit is contained in:
Sebastien Bourdeauducq 2018-05-18 17:41:32 +08:00
parent 8a988d0feb
commit b10d3ee4b4
10 changed files with 70 additions and 117 deletions

View File

@ -35,6 +35,8 @@ ARTIQ-4
* ``artiq.coredevice.dds`` has been renamed to ``artiq.coredevice.ad9914`` and * ``artiq.coredevice.dds`` has been renamed to ``artiq.coredevice.ad9914`` and
simplified. DDS batch mode is no longer supported. The ``core_dds`` device simplified. DDS batch mode is no longer supported. The ``core_dds`` device
is no longer necessary. is no longer necessary.
* The configuration entry ``startup_clock`` is renamed ``rtio_clock``. Switching
clocks dynamically (i.e. without device restart) is no longer supported.
ARTIQ-3 ARTIQ-3

View File

@ -16,7 +16,6 @@ logger = logging.getLogger(__name__)
class Request(Enum): class Request(Enum):
SystemInfo = 3 SystemInfo = 3
SwitchClock = 4
LoadKernel = 5 LoadKernel = 5
RunKernel = 6 RunKernel = 6
@ -27,8 +26,6 @@ class Request(Enum):
class Reply(Enum): class Reply(Enum):
SystemInfo = 2 SystemInfo = 2
ClockSwitchCompleted = 3
ClockSwitchFailed = 4
LoadCompleted = 5 LoadCompleted = 5
LoadFailed = 6 LoadFailed = 6
@ -60,9 +57,6 @@ class CommKernelDummy:
def __init__(self): def __init__(self):
pass pass
def switch_clock(self, external):
pass
def load(self, kernel_library): def load(self, kernel_library):
pass pass
@ -237,12 +231,6 @@ class CommKernel:
if not finished_cleanly: if not finished_cleanly:
logger.warning("Previous kernel did not cleanly finish") logger.warning("Previous kernel did not cleanly finish")
def switch_clock(self, external):
self._write_header(Request.SwitchClock)
self._write_int8(external)
self._read_empty(Reply.ClockSwitchCompleted)
def load(self, kernel_library): def load(self, kernel_library):
self._write_header(Request.LoadKernel) self._write_header(Request.LoadKernel)
self._write_bytes(kernel_library) self._write_bytes(kernel_library)

View File

@ -62,8 +62,6 @@ class Core:
clocked at 125MHz and a SERDES multiplication factor of 8, the clocked at 125MHz and a SERDES multiplication factor of 8, the
reference period is 1ns. reference period is 1ns.
The time machine unit is equal to this period. The time machine unit is equal to this period.
:param external_clock: whether the core device should switch to its
external RTIO clock input instead of using its internal oscillator.
:param ref_multiplier: ratio between the RTIO fine timestamp frequency :param ref_multiplier: ratio between the RTIO fine timestamp frequency
and the RTIO coarse timestamp frequency (e.g. SERDES multiplication and the RTIO coarse timestamp frequency (e.g. SERDES multiplication
factor). factor).
@ -71,13 +69,10 @@ class Core:
kernel_invariants = { kernel_invariants = {
"core", "ref_period", "coarse_ref_period", "ref_multiplier", "core", "ref_period", "coarse_ref_period", "ref_multiplier",
"external_clock",
} }
def __init__(self, dmgr, host, ref_period, external_clock=False, def __init__(self, dmgr, host, ref_period, ref_multiplier=8):
ref_multiplier=8):
self.ref_period = ref_period self.ref_period = ref_period
self.external_clock = external_clock
self.ref_multiplier = ref_multiplier self.ref_multiplier = ref_multiplier
self.coarse_ref_period = ref_period*ref_multiplier self.coarse_ref_period = ref_period*ref_multiplier
if host is None: if host is None:
@ -129,7 +124,6 @@ class Core:
if self.first_run: if self.first_run:
self.comm.check_system_info() self.comm.check_system_info()
self.comm.switch_clock(self.external_clock)
self.first_run = False self.first_run = False
self.comm.load(kernel_library) self.comm.load(kernel_library)

View File

@ -64,7 +64,6 @@ fn write_sync<W>(writer: &mut W) -> Result<(), IoError<W::WriteError>>
#[derive(Debug)] #[derive(Debug)]
pub enum Request { pub enum Request {
SystemInfo, SystemInfo,
SwitchClock(u8),
LoadKernel(Vec<u8>), LoadKernel(Vec<u8>),
RunKernel, RunKernel,
@ -87,8 +86,6 @@ pub enum Reply<'a> {
ident: &'a str, ident: &'a str,
finished_cleanly: bool finished_cleanly: bool
}, },
ClockSwitchCompleted,
ClockSwitchFailed,
LoadCompleted, LoadCompleted,
LoadFailed(&'a str), LoadFailed(&'a str),
@ -118,10 +115,7 @@ impl Request {
{ {
read_sync(reader)?; read_sync(reader)?;
Ok(match reader.read_u8()? { Ok(match reader.read_u8()? {
// 1-2, 13 were log requests
3 => Request::SystemInfo, 3 => Request::SystemInfo,
4 => Request::SwitchClock(reader.read_u8()?),
5 => Request::LoadKernel(reader.read_bytes()?), 5 => Request::LoadKernel(reader.read_bytes()?),
6 => Request::RunKernel, 6 => Request::RunKernel,
@ -141,10 +135,6 @@ impl Request {
function: reader.read_string()? function: reader.read_string()?
}, },
// 9-12 were flash requests
// 14 was hotswap request
ty => return Err(Error::UnknownPacket(ty)) ty => return Err(Error::UnknownPacket(ty))
}) })
} }
@ -156,20 +146,12 @@ impl<'a> Reply<'a> {
{ {
write_sync(writer)?; write_sync(writer)?;
match *self { match *self {
// 1 was log reply
Reply::SystemInfo { ident, finished_cleanly } => { Reply::SystemInfo { ident, finished_cleanly } => {
writer.write_u8(2)?; writer.write_u8(2)?;
writer.write(b"AROR")?; writer.write(b"AROR")?;
writer.write_string(ident)?; writer.write_string(ident)?;
writer.write_u8(finished_cleanly as u8)?; writer.write_u8(finished_cleanly as u8)?;
}, },
Reply::ClockSwitchCompleted => {
writer.write_u8(3)?;
},
Reply::ClockSwitchFailed => {
writer.write_u8(4)?;
},
Reply::LoadCompleted => { Reply::LoadCompleted => {
writer.write_u8(5)?; writer.write_u8(5)?;
@ -209,16 +191,12 @@ impl<'a> Reply<'a> {
writer.write_u8(async as u8)?; writer.write_u8(async as u8)?;
}, },
// 11-13 were flash requests
Reply::WatchdogExpired => { Reply::WatchdogExpired => {
writer.write_u8(14)?; writer.write_u8(14)?;
}, },
Reply::ClockFailure => { Reply::ClockFailure => {
writer.write_u8(15)?; writer.write_u8(15)?;
}, },
// 16 was hotswap imminent reply
} }
Ok(()) Ok(())
} }

View File

@ -1,28 +1,32 @@
use board_misoc::{csr, config}; use board_misoc::csr;
#[cfg(has_rtio_clock_switch)]
use board_misoc::config;
use sched::Io; use sched::Io;
#[cfg(has_rtio_crg)] #[cfg(has_rtio_crg)]
pub mod crg { pub mod crg {
use board_misoc::{clock, csr}; use board_misoc::{clock, csr};
pub fn init() {
unsafe { csr::rtio_crg::pll_reset_write(0) }
}
pub fn check() -> bool { pub fn check() -> bool {
unsafe { csr::rtio_crg::pll_locked_read() != 0 } unsafe { csr::rtio_crg::pll_locked_read() != 0 }
} }
pub fn switch_clock(clk: u8) -> bool { #[cfg(has_rtio_clock_switch)]
pub fn init(clk: u8) -> bool {
unsafe { unsafe {
let cur_clk = csr::rtio_crg::clock_sel_read();
if clk != cur_clk {
csr::rtio_crg::pll_reset_write(1); csr::rtio_crg::pll_reset_write(1);
csr::rtio_crg::clock_sel_write(clk); csr::rtio_crg::clock_sel_write(clk);
csr::rtio_crg::pll_reset_write(0); csr::rtio_crg::pll_reset_write(0);
} }
clock::spin_us(150);
return check()
} }
#[cfg(not(has_rtio_clock_switch))]
pub fn init() -> bool {
unsafe {
csr::rtio_crg::pll_reset_write(0);
}
clock::spin_us(150); clock::spin_us(150);
return check() return check()
} }
@ -30,9 +34,7 @@ pub mod crg {
#[cfg(not(has_rtio_crg))] #[cfg(not(has_rtio_crg))]
pub mod crg { pub mod crg {
pub fn init() {}
pub fn check() -> bool { true } pub fn check() -> bool { true }
pub fn switch_clock(_clk: u8) -> bool { true }
} }
#[cfg(has_drtio)] #[cfg(has_drtio)]
@ -227,40 +229,43 @@ fn async_error_thread(io: Io) {
} }
pub fn startup(io: &Io) { pub fn startup(io: &Io) {
crg::init(); #[cfg(has_rtio_crg)]
{
#[cfg(has_rtio_clock_switch)]
{
#[derive(Debug)] #[derive(Debug)]
enum RtioClock { enum RtioClock {
Internal = 0, Internal = 0,
External = 1 External = 1
}; };
let clk = config::read("startup_clock", |result| { let clk = config::read("rtio_clock", |result| {
match result { match result {
Ok(b"i") => { Ok(b"i") => {
info!("using internal startup RTIO clock"); info!("using internal RTIO clock");
RtioClock::Internal RtioClock::Internal
}, },
Ok(b"e") => { Ok(b"e") => {
info!("using external startup RTIO clock"); info!("using external RTIO clock");
RtioClock::External RtioClock::External
}, },
Err(_) => { _ => {
info!("using internal startup RTIO clock (by default)"); info!("using internal RTIO clock (by default)");
RtioClock::Internal RtioClock::Internal
}, },
Ok(_) => {
error!("unrecognized startup_clock configuration entry, \
using internal RTIO clock");
RtioClock::Internal
}
} }
}); });
if !crg::switch_clock(clk as u8) { if !crg::init(clk as u8) {
error!("startup RTIO clock failed"); error!("RTIO clock failed");
warn!("this may cause the system initialization to fail"); }
warn!("fix clocking and reset the device"); }
#[cfg(not(has_rtio_clock_switch))]
{
if !crg::init() {
error!("RTIO clock failed");
}
}
} }
drtio::startup(io); drtio::startup(io);

View File

@ -250,24 +250,6 @@ fn process_host_message(io: &Io,
session.congress.finished_cleanly.set(true) session.congress.finished_cleanly.set(true)
} }
host::Request::SwitchClock(clk) => {
if session.running() {
unexpected!("attempted to switch RTIO clock while a kernel was running")
}
#[cfg(has_rtio_core)]
{
if rtio_mgt::crg::switch_clock(clk) {
host_write(stream, host::Reply::ClockSwitchCompleted)?;
} else {
host_write(stream, host::Reply::ClockSwitchFailed)?;
}
}
#[cfg(not(has_rtio_core))]
host_write(stream, host::Reply::ClockSwitchFailed)?
}
host::Request::LoadKernel(kernel) => host::Request::LoadKernel(kernel) =>
match unsafe { kern_load(io, session, &kernel) } { match unsafe { kern_load(io, session, &kernel) } {
Ok(()) => host_write(stream, host::Reply::LoadCompleted)?, Ok(()) => host_write(stream, host::Reply::LoadCompleted)?,

View File

@ -29,25 +29,22 @@ from artiq import __version__ as artiq_version
class _RTIOCRG(Module, AutoCSR): class _RTIOCRG(Module, AutoCSR):
def __init__(self, platform, rtio_internal_clk): def __init__(self, platform):
self._clock_sel = CSRStorage()
self._pll_reset = CSRStorage(reset=1) self._pll_reset = CSRStorage(reset=1)
self._pll_locked = CSRStatus() self._pll_locked = CSRStatus()
self.clock_domains.cd_rtio = ClockDomain() self.clock_domains.cd_rtio = ClockDomain()
self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True)
rtio_external_clk = Signal()
clk_synth_se = Signal()
clk_synth = platform.request("si5324_clkout_fabric") clk_synth = platform.request("si5324_clkout_fabric")
clk_synth_se = Signal()
clk_synth_buffered = Signal()
platform.add_period_constraint(clk_synth.p, 8.0) platform.add_period_constraint(clk_synth.p, 8.0)
self.specials += [ self.specials += [
Instance("IBUFGDS", Instance("IBUFGDS",
p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE", p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE",
i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se), i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se),
Instance("BUFG", i_I=clk_synth_se, o_O=rtio_external_clk), Instance("BUFG", i_I=clk_synth_se, o_O=clk_synth_buffered),
] ]
platform.add_false_path_constraints(
rtio_external_clk, rtio_internal_clk)
pll_locked = Signal() pll_locked = Signal()
rtio_clk = Signal() rtio_clk = Signal()
@ -59,9 +56,9 @@ class _RTIOCRG(Module, AutoCSR):
p_REF_JITTER1=0.01, p_REF_JITTER1=0.01,
p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0,
i_CLKIN1=rtio_internal_clk, i_CLKIN2=rtio_external_clk, i_CLKIN2=clk_synth_buffered,
# Warning: CLKINSEL=0 means CLKIN2 is selected # Warning: CLKINSEL=0 means CLKIN2 is selected
i_CLKINSEL=~self._clock_sel.storage, i_CLKINSEL=0,
# VCO @ 1GHz when using 125MHz input # VCO @ 1GHz when using 125MHz input
p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1,
@ -123,7 +120,7 @@ class _StandaloneBase(MiniSoC, AMPSoC):
self.config["SI5324_SOFT_RESET"] = None self.config["SI5324_SOFT_RESET"] = None
def add_rtio(self, rtio_channels): def add_rtio(self, rtio_channels):
self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) self.submodules.rtio_crg = _RTIOCRG(self.platform)
self.csr_devices.append("rtio_crg") self.csr_devices.append("rtio_crg")
fix_serdes_timing_path(self.platform) fix_serdes_timing_path(self.platform)
self.submodules.rtio_core = rtio.Core(rtio_channels) self.submodules.rtio_core = rtio.Core(rtio_channels)

View File

@ -256,6 +256,7 @@ class _StandaloneBase(MiniSoC, AMPSoC):
def add_rtio(self, rtio_channels): def add_rtio(self, rtio_channels):
self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk)
self.csr_devices.append("rtio_crg") self.csr_devices.append("rtio_crg")
self.config["HAS_RTIO_CLOCK_SWITCH"] = None
self.submodules.rtio_core = rtio.Core(rtio_channels) self.submodules.rtio_core = rtio.Core(rtio_channels)
self.csr_devices.append("rtio_core") self.csr_devices.append("rtio_core")
self.submodules.rtio = rtio.KernelInitiator() self.submodules.rtio = rtio.KernelInitiator()
@ -502,6 +503,7 @@ class SMA_SPI(_StandaloneBase):
self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk, self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk,
use_sma=False) use_sma=False)
self.csr_devices.append("rtio_crg") self.csr_devices.append("rtio_crg")
self.config["HAS_RTIO_CLOCK_SWITCH"] = None
self.submodules.rtio_core = rtio.Core(rtio_channels) self.submodules.rtio_core = rtio.Core(rtio_channels)
self.csr_devices.append("rtio_core") self.csr_devices.append("rtio_core")
self.submodules.rtio = rtio.KernelInitiator() self.submodules.rtio = rtio.KernelInitiator()

View File

@ -159,6 +159,11 @@ To avoid I/O contention, the startup kernel should first program the TCA6424A ex
See :mod:`artiq.coredevice.i2c` for more details. See :mod:`artiq.coredevice.i2c` for more details.
Clocking
++++++++
The KC705 supports an internal 125MHz RTIO clock (based on its crystal oscillator) and an external clock, that can be selected using the ``rtio_clock`` configuration entry.
Kasli Kasli
----- -----

View File

@ -189,12 +189,12 @@ The startup kernel is executed once when the core device powers up. It should in
For DRTIO systems, the startup kernel should wait until the desired links are up, using :meth:`artiq.coredevice.Core.get_drtio_link_status`. For DRTIO systems, the startup kernel should wait until the desired links are up, using :meth:`artiq.coredevice.Core.get_drtio_link_status`.
* (optional) Select the startup clock * (optional) Select the RTIO clock source
The core device may use either an external clock signal or its internal clock. This clock can be switched dynamically after the PC is connected using the ``external_clock`` parameter of the core device driver; however, one may want to select the clock at power-up so that it is used for the startup and idle kernels. Use one of these commands: :: Some core devices may use either an external clock signal or their internal clock. The clock is selected at power-up. Use one of these commands: ::
$ artiq_coreconfig write -s startup_clock i # internal clock (default) $ artiq_coreconfig write -s rtio_clock i # internal clock (default)
$ artiq_coreconfig write -s startup_clock e # external clock $ artiq_coreconfig write -s rtio_clock e # external clock
.. rubric:: Footnotes .. rubric:: Footnotes