mirror of https://github.com/m-labs/artiq.git
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:
parent
8a988d0feb
commit
b10d3ee4b4
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
let clk = config::read("startup_clock", |result| {
|
||||
let clk = config::read("rtio_clock", |result| {
|
||||
match result {
|
||||
Ok(b"i") => {
|
||||
info!("using internal startup RTIO clock");
|
||||
info!("using internal RTIO clock");
|
||||
RtioClock::Internal
|
||||
},
|
||||
Ok(b"e") => {
|
||||
info!("using external startup RTIO clock");
|
||||
info!("using external RTIO clock");
|
||||
RtioClock::External
|
||||
},
|
||||
Err(_) => {
|
||||
info!("using internal startup RTIO clock (by default)");
|
||||
_ => {
|
||||
info!("using internal RTIO clock (by default)");
|
||||
RtioClock::Internal
|
||||
},
|
||||
Ok(_) => {
|
||||
error!("unrecognized startup_clock configuration entry, \
|
||||
using internal RTIO clock");
|
||||
RtioClock::Internal
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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");
|
||||
if !crg::init(clk as u8) {
|
||||
error!("RTIO clock failed");
|
||||
}
|
||||
}
|
||||
#[cfg(not(has_rtio_clock_switch))]
|
||||
{
|
||||
if !crg::init() {
|
||||
error!("RTIO clock failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drtio::startup(io);
|
||||
|
|
|
@ -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)?,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
-----
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue