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
simplified. DDS batch mode is no longer supported. The ``core_dds`` device
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

View File

@ -16,7 +16,6 @@ logger = logging.getLogger(__name__)
class Request(Enum):
SystemInfo = 3
SwitchClock = 4
LoadKernel = 5
RunKernel = 6
@ -27,8 +26,6 @@ class Request(Enum):
class Reply(Enum):
SystemInfo = 2
ClockSwitchCompleted = 3
ClockSwitchFailed = 4
LoadCompleted = 5
LoadFailed = 6
@ -60,9 +57,6 @@ class CommKernelDummy:
def __init__(self):
pass
def switch_clock(self, external):
pass
def load(self, kernel_library):
pass
@ -237,12 +231,6 @@ class CommKernel:
if not finished_cleanly:
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):
self._write_header(Request.LoadKernel)
self._write_bytes(kernel_library)

View File

@ -62,8 +62,6 @@ class Core:
clocked at 125MHz and a SERDES multiplication factor of 8, the
reference period is 1ns.
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
and the RTIO coarse timestamp frequency (e.g. SERDES multiplication
factor).
@ -71,13 +69,10 @@ class Core:
kernel_invariants = {
"core", "ref_period", "coarse_ref_period", "ref_multiplier",
"external_clock",
}
def __init__(self, dmgr, host, ref_period, external_clock=False,
ref_multiplier=8):
def __init__(self, dmgr, host, ref_period, ref_multiplier=8):
self.ref_period = ref_period
self.external_clock = external_clock
self.ref_multiplier = ref_multiplier
self.coarse_ref_period = ref_period*ref_multiplier
if host is None:
@ -129,7 +124,6 @@ class Core:
if self.first_run:
self.comm.check_system_info()
self.comm.switch_clock(self.external_clock)
self.first_run = False
self.comm.load(kernel_library)

View File

@ -64,7 +64,6 @@ fn write_sync<W>(writer: &mut W) -> Result<(), IoError<W::WriteError>>
#[derive(Debug)]
pub enum Request {
SystemInfo,
SwitchClock(u8),
LoadKernel(Vec<u8>),
RunKernel,
@ -87,8 +86,6 @@ pub enum Reply<'a> {
ident: &'a str,
finished_cleanly: bool
},
ClockSwitchCompleted,
ClockSwitchFailed,
LoadCompleted,
LoadFailed(&'a str),
@ -118,10 +115,7 @@ impl Request {
{
read_sync(reader)?;
Ok(match reader.read_u8()? {
// 1-2, 13 were log requests
3 => Request::SystemInfo,
4 => Request::SwitchClock(reader.read_u8()?),
5 => Request::LoadKernel(reader.read_bytes()?),
6 => Request::RunKernel,
@ -141,10 +135,6 @@ impl Request {
function: reader.read_string()?
},
// 9-12 were flash requests
// 14 was hotswap request
ty => return Err(Error::UnknownPacket(ty))
})
}
@ -156,20 +146,12 @@ impl<'a> Reply<'a> {
{
write_sync(writer)?;
match *self {
// 1 was log reply
Reply::SystemInfo { ident, finished_cleanly } => {
writer.write_u8(2)?;
writer.write(b"AROR")?;
writer.write_string(ident)?;
writer.write_u8(finished_cleanly as u8)?;
},
Reply::ClockSwitchCompleted => {
writer.write_u8(3)?;
},
Reply::ClockSwitchFailed => {
writer.write_u8(4)?;
},
Reply::LoadCompleted => {
writer.write_u8(5)?;
@ -209,16 +191,12 @@ impl<'a> Reply<'a> {
writer.write_u8(async as u8)?;
},
// 11-13 were flash requests
Reply::WatchdogExpired => {
writer.write_u8(14)?;
},
Reply::ClockFailure => {
writer.write_u8(15)?;
},
// 16 was hotswap imminent reply
}
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;
#[cfg(has_rtio_crg)]
pub mod crg {
use board_misoc::{clock, csr};
pub fn init() {
unsafe { csr::rtio_crg::pll_reset_write(0) }
}
pub fn check() -> bool {
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 {
let cur_clk = csr::rtio_crg::clock_sel_read();
if clk != cur_clk {
csr::rtio_crg::pll_reset_write(1);
csr::rtio_crg::clock_sel_write(clk);
csr::rtio_crg::pll_reset_write(0);
}
csr::rtio_crg::pll_reset_write(1);
csr::rtio_crg::clock_sel_write(clk);
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);
return check()
}
@ -30,9 +34,7 @@ pub mod crg {
#[cfg(not(has_rtio_crg))]
pub mod crg {
pub fn init() {}
pub fn check() -> bool { true }
pub fn switch_clock(_clk: u8) -> bool { true }
}
#[cfg(has_drtio)]
@ -227,40 +229,43 @@ fn async_error_thread(io: Io) {
}
pub fn startup(io: &Io) {
crg::init();
#[cfg(has_rtio_crg)]
{
#[cfg(has_rtio_clock_switch)]
{
#[derive(Debug)]
enum RtioClock {
Internal = 0,
External = 1
};
#[derive(Debug)]
enum RtioClock {
Internal = 0,
External = 1
};
let clk = config::read("rtio_clock", |result| {
match result {
Ok(b"i") => {
info!("using internal RTIO clock");
RtioClock::Internal
},
Ok(b"e") => {
info!("using external RTIO clock");
RtioClock::External
},
_ => {
info!("using internal RTIO clock (by default)");
RtioClock::Internal
},
}
});
let clk = config::read("startup_clock", |result| {
match result {
Ok(b"i") => {
info!("using internal startup RTIO clock");
RtioClock::Internal
},
Ok(b"e") => {
info!("using external startup RTIO clock");
RtioClock::External
},
Err(_) => {
info!("using internal startup RTIO clock (by default)");
RtioClock::Internal
},
Ok(_) => {
error!("unrecognized startup_clock configuration entry, \
using internal RTIO clock");
RtioClock::Internal
if !crg::init(clk as u8) {
error!("RTIO clock failed");
}
}
#[cfg(not(has_rtio_clock_switch))]
{
if !crg::init() {
error!("RTIO clock failed");
}
}
});
if !crg::switch_clock(clk as u8) {
error!("startup RTIO clock failed");
warn!("this may cause the system initialization to fail");
warn!("fix clocking and reset the device");
}
drtio::startup(io);

View File

@ -250,24 +250,6 @@ fn process_host_message(io: &Io,
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) =>
match unsafe { kern_load(io, session, &kernel) } {
Ok(()) => host_write(stream, host::Reply::LoadCompleted)?,

View File

@ -29,25 +29,22 @@ from artiq import __version__ as artiq_version
class _RTIOCRG(Module, AutoCSR):
def __init__(self, platform, rtio_internal_clk):
self._clock_sel = CSRStorage()
def __init__(self, platform):
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()
clk_synth_se = Signal()
clk_synth = platform.request("si5324_clkout_fabric")
clk_synth_se = Signal()
clk_synth_buffered = Signal()
platform.add_period_constraint(clk_synth.p, 8.0)
self.specials += [
Instance("IBUFGDS",
p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE",
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()
rtio_clk = Signal()
@ -59,9 +56,9 @@ class _RTIOCRG(Module, AutoCSR):
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,
i_CLKIN2=clk_synth_buffered,
# Warning: CLKINSEL=0 means CLKIN2 is selected
i_CLKINSEL=~self._clock_sel.storage,
i_CLKINSEL=0,
# VCO @ 1GHz when using 125MHz input
p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1,
@ -123,7 +120,7 @@ class _StandaloneBase(MiniSoC, AMPSoC):
self.config["SI5324_SOFT_RESET"] = None
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")
fix_serdes_timing_path(self.platform)
self.submodules.rtio_core = rtio.Core(rtio_channels)

View File

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

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`.
* (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 startup_clock e # external clock
$ artiq_coreconfig write -s rtio_clock i # internal clock (default)
$ artiq_coreconfig write -s rtio_clock e # external clock
.. rubric:: Footnotes