forked from M-Labs/artiq
rtio: add support for latency compensation in phy
* if multiple RTIO channels influence the same data stream and physical output channel (see SAWG) differential latency needs to be compensated * this is a NOP for phys with zero delay (default) * if delay==1, it adds one timestamp-wide register * if delay >1, it adds one adder and one register * latency compensation using (~10-50 deep) delay lines is about as expensive as a single adder+register but very tedious to implement
This commit is contained in:
parent
7be27d7116
commit
6cdb96c5e0
|
@ -159,10 +159,18 @@ class _OutputManager(Module):
|
||||||
)
|
)
|
||||||
self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))
|
self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))
|
||||||
|
|
||||||
|
# latency compensation
|
||||||
|
if interface.delay:
|
||||||
|
counter_rtio = Signal.like(counter.value_rtio)
|
||||||
|
self.sync.rio += counter_rtio.eq(counter.value_rtio -
|
||||||
|
interface.delay + 1)
|
||||||
|
else:
|
||||||
|
counter_rtio = counter.value_rtio
|
||||||
|
|
||||||
# FIFO read through buffer
|
# FIFO read through buffer
|
||||||
self.comb += [
|
self.comb += [
|
||||||
dout_ack.eq(
|
dout_ack.eq(
|
||||||
dout.timestamp[fine_ts_width:] == counter.value_rtio),
|
dout.timestamp[fine_ts_width:] == counter_rtio),
|
||||||
interface.stb.eq(dout_stb & dout_ack)
|
interface.stb.eq(dout_stb & dout_ack)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -210,14 +218,22 @@ class _InputManager(Module):
|
||||||
fifo_out.raw_bits().eq(fifo.dout)
|
fifo_out.raw_bits().eq(fifo.dout)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# latency compensation
|
||||||
|
if interface.delay:
|
||||||
|
counter_rtio = Signal.like(counter.value_rtio)
|
||||||
|
self.sync.rio += counter_rtio.eq(counter.value_rtio -
|
||||||
|
interface.delay + 1)
|
||||||
|
else:
|
||||||
|
counter_rtio = counter.value_rtio
|
||||||
|
|
||||||
# FIFO write
|
# FIFO write
|
||||||
if data_width:
|
if data_width:
|
||||||
self.comb += fifo_in.data.eq(interface.data)
|
self.comb += fifo_in.data.eq(interface.data)
|
||||||
if interface.timestamped:
|
if interface.timestamped:
|
||||||
if fine_ts_width:
|
if fine_ts_width:
|
||||||
full_ts = Cat(interface.fine_ts, counter.value_rtio)
|
full_ts = Cat(interface.fine_ts, counter_rtio)
|
||||||
else:
|
else:
|
||||||
full_ts = counter.value_rtio
|
full_ts = counter_rtio
|
||||||
self.comb += fifo_in.timestamp.eq(full_ts)
|
self.comb += fifo_in.timestamp.eq(full_ts)
|
||||||
self.comb += fifo.we.eq(interface.stb)
|
self.comb += fifo.we.eq(interface.stb)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@ from migen import *
|
||||||
|
|
||||||
class OInterface:
|
class OInterface:
|
||||||
def __init__(self, data_width, address_width=0,
|
def __init__(self, data_width, address_width=0,
|
||||||
fine_ts_width=0, enable_replace=True):
|
fine_ts_width=0, enable_replace=True,
|
||||||
|
delay=0):
|
||||||
self.stb = Signal()
|
self.stb = Signal()
|
||||||
self.busy = Signal()
|
self.busy = Signal()
|
||||||
|
|
||||||
|
@ -16,17 +17,22 @@ class OInterface:
|
||||||
|
|
||||||
self.enable_replace = enable_replace
|
self.enable_replace = enable_replace
|
||||||
|
|
||||||
|
if delay < 0:
|
||||||
|
raise ValueError("only positive delays allowed", delay)
|
||||||
|
self.delay = delay
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def like(cls, other):
|
def like(cls, other):
|
||||||
return cls(get_data_width(other),
|
return cls(get_data_width(other),
|
||||||
get_address_width(other),
|
get_address_width(other),
|
||||||
get_fine_ts_width(other),
|
get_fine_ts_width(other),
|
||||||
other.enable_replace)
|
other.enable_replace,
|
||||||
|
other.delay)
|
||||||
|
|
||||||
|
|
||||||
class IInterface:
|
class IInterface:
|
||||||
def __init__(self, data_width,
|
def __init__(self, data_width,
|
||||||
timestamped=True, fine_ts_width=0):
|
timestamped=True, fine_ts_width=0, delay=0):
|
||||||
self.stb = Signal()
|
self.stb = Signal()
|
||||||
|
|
||||||
if data_width:
|
if data_width:
|
||||||
|
@ -34,14 +40,18 @@ class IInterface:
|
||||||
if fine_ts_width:
|
if fine_ts_width:
|
||||||
self.fine_ts = Signal(fine_ts_width)
|
self.fine_ts = Signal(fine_ts_width)
|
||||||
|
|
||||||
self.timestamped = timestamped
|
|
||||||
assert(not fine_ts_width or timestamped)
|
assert(not fine_ts_width or timestamped)
|
||||||
|
self.timestamped = timestamped
|
||||||
|
if delay < 0:
|
||||||
|
raise ValueError("only positive delays")
|
||||||
|
self.delay = delay
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def like(cls, other):
|
def like(cls, other):
|
||||||
return cls(get_data_width(other),
|
return cls(get_data_width(other),
|
||||||
other.timestamped,
|
other.timestamped,
|
||||||
get_fine_ts_width(other))
|
get_fine_ts_width(other),
|
||||||
|
delay)
|
||||||
|
|
||||||
|
|
||||||
class Interface:
|
class Interface:
|
||||||
|
|
Loading…
Reference in New Issue