2017-03-07 00:46:59 +08:00
|
|
|
"""Real-time I/O scheduler for satellites"""
|
|
|
|
|
2016-10-10 23:12:12 +08:00
|
|
|
from migen import *
|
|
|
|
from migen.genlib.fifo import SyncFIFOBuffered
|
2016-10-11 17:59:22 +08:00
|
|
|
from migen.genlib.record import *
|
2016-10-10 23:12:12 +08:00
|
|
|
|
|
|
|
from artiq.gateware.rtio import rtlink
|
|
|
|
|
|
|
|
|
2017-03-07 00:46:59 +08:00
|
|
|
class IOS(Module):
|
|
|
|
def __init__(self, rt_packet, channels, max_fine_ts_width, full_ts_width):
|
2017-03-13 23:54:44 +08:00
|
|
|
self.rt_packet = rt_packet
|
|
|
|
self.max_fine_ts_width = max_fine_ts_width
|
|
|
|
|
|
|
|
self.tsc = Signal(full_ts_width - max_fine_ts_width)
|
2016-11-24 00:09:53 +08:00
|
|
|
self.sync.rtio += \
|
2017-03-07 00:46:59 +08:00
|
|
|
If(rt_packet.tsc_load,
|
2017-03-13 23:54:44 +08:00
|
|
|
self.tsc.eq(rt_packet.tsc_load_value)
|
2016-10-11 17:59:22 +08:00
|
|
|
).Else(
|
2017-03-13 23:54:44 +08:00
|
|
|
self.tsc.eq(self.tsc + 1)
|
2016-10-11 17:59:22 +08:00
|
|
|
)
|
2017-03-13 23:54:44 +08:00
|
|
|
self.comb += rt_packet.tsc_input.eq(self.tsc)
|
2016-10-11 17:59:22 +08:00
|
|
|
|
|
|
|
for n, channel in enumerate(channels):
|
2017-03-13 23:54:44 +08:00
|
|
|
self.add_output(n, channel)
|
|
|
|
self.add_input(n, channel)
|
|
|
|
|
|
|
|
def add_output(self, n, channel):
|
|
|
|
rt_packet = self.rt_packet
|
|
|
|
max_fine_ts_width = self.max_fine_ts_width
|
|
|
|
|
|
|
|
interface = channel.interface.o
|
|
|
|
data_width = rtlink.get_data_width(interface)
|
|
|
|
address_width = rtlink.get_address_width(interface)
|
|
|
|
fine_ts_width = rtlink.get_fine_ts_width(interface)
|
|
|
|
assert fine_ts_width <= max_fine_ts_width
|
|
|
|
|
|
|
|
# FIFO
|
|
|
|
ev_layout = []
|
|
|
|
if data_width:
|
|
|
|
ev_layout.append(("data", data_width))
|
|
|
|
if address_width:
|
|
|
|
ev_layout.append(("address", address_width))
|
|
|
|
ev_layout.append(("timestamp", len(self.tsc) + fine_ts_width))
|
|
|
|
|
|
|
|
fifo = ClockDomainsRenamer("rio")(
|
|
|
|
SyncFIFOBuffered(layout_len(ev_layout), channel.ofifo_depth))
|
|
|
|
self.submodules += fifo
|
|
|
|
fifo_in = Record(ev_layout)
|
|
|
|
fifo_out = Record(ev_layout)
|
|
|
|
self.comb += [
|
|
|
|
fifo.din.eq(fifo_in.raw_bits()),
|
|
|
|
fifo_out.raw_bits().eq(fifo.dout)
|
|
|
|
]
|
|
|
|
|
|
|
|
# FIFO level
|
|
|
|
self.sync.rio += \
|
|
|
|
If(rt_packet.fifo_space_update &
|
|
|
|
(rt_packet.fifo_space_channel == n),
|
|
|
|
rt_packet.fifo_space.eq(channel.ofifo_depth - fifo.level))
|
|
|
|
|
|
|
|
# FIFO write
|
|
|
|
self.comb += fifo.we.eq(rt_packet.write_stb
|
|
|
|
& (rt_packet.write_channel == n))
|
|
|
|
self.sync.rio += [
|
|
|
|
If(rt_packet.write_overflow_ack,
|
|
|
|
rt_packet.write_overflow.eq(0)),
|
|
|
|
If(rt_packet.write_underflow_ack,
|
|
|
|
rt_packet.write_underflow.eq(0)),
|
|
|
|
If(fifo.we,
|
|
|
|
If(~fifo.writable, rt_packet.write_overflow.eq(1)),
|
|
|
|
If(rt_packet.write_timestamp[max_fine_ts_width:] < (self.tsc + 4),
|
|
|
|
rt_packet.write_underflow.eq(1)
|
2016-10-11 17:59:22 +08:00
|
|
|
)
|
2017-03-13 23:54:44 +08:00
|
|
|
)
|
|
|
|
]
|
|
|
|
if data_width:
|
|
|
|
self.comb += fifo_in.data.eq(rt_packet.write_data)
|
|
|
|
if address_width:
|
|
|
|
self.comb += fifo_in.address.eq(rt_packet.write_address)
|
|
|
|
self.comb += fifo_in.timestamp.eq(
|
|
|
|
rt_packet.write_timestamp[max_fine_ts_width-fine_ts_width:])
|
|
|
|
|
|
|
|
# FIFO read
|
|
|
|
self.sync.rio += [
|
|
|
|
fifo.re.eq(0),
|
|
|
|
interface.stb.eq(0),
|
|
|
|
If(fifo.readable &
|
|
|
|
(fifo_out.timestamp[fine_ts_width:] == self.tsc),
|
|
|
|
fifo.re.eq(1),
|
|
|
|
interface.stb.eq(1)
|
|
|
|
)
|
|
|
|
]
|
|
|
|
if data_width:
|
|
|
|
self.sync.rio += interface.data.eq(fifo_out.data)
|
|
|
|
if address_width:
|
|
|
|
self.sync.rio += interface.address.eq(fifo_out.address)
|
|
|
|
if fine_ts_width:
|
|
|
|
self.sync.rio += interface.fine_ts.eq(fifo_out.timestamp[:fine_ts_width])
|
|
|
|
|
|
|
|
def add_input(self, n, channel):
|
|
|
|
interface = channel.interface.i
|
|
|
|
if interface is None:
|
|
|
|
return
|
|
|
|
data_width = rtlink.get_data_width(interface)
|
|
|
|
fine_ts_width = rtlink.get_fine_ts_width(interface)
|
|
|
|
|
|
|
|
selected = Signal()
|
|
|
|
self.comb += selected.eq(rt_packet.read_channel == n)
|
|
|
|
|
|
|
|
# FIFO
|
|
|
|
ev_layout = []
|
|
|
|
if data_width:
|
|
|
|
ev_layout.append(("data", data_width))
|
|
|
|
if interface.timestamped:
|
|
|
|
ev_layout.append(("timestamp", len(self.tsc) + fine_ts_width))
|
|
|
|
|
|
|
|
fifo = ClockDomainsRenamer("rio")(
|
|
|
|
SyncFIFOBuffered(layout_len(ev_layout), channel.ififo_depth))
|
|
|
|
self.submodules += fifo
|
|
|
|
fifo_in = Record(ev_layout)
|
|
|
|
fifo_out = Record(ev_layout)
|
|
|
|
self.comb += [
|
|
|
|
fifo.din.eq(fifo_in.raw_bits()),
|
|
|
|
fifo_out.raw_bits().eq(fifo.dout)
|
|
|
|
]
|
|
|
|
|
|
|
|
# FIFO write
|
|
|
|
if data_width:
|
|
|
|
self.comb += fifo_in.data.eq(interface.data)
|
|
|
|
if interface.timestamped:
|
2016-10-11 17:59:22 +08:00
|
|
|
if fine_ts_width:
|
2017-03-13 23:54:44 +08:00
|
|
|
full_ts = Cat(interface.fine_ts, self.tsc)
|
|
|
|
else:
|
|
|
|
full_ts = self.tsc
|
|
|
|
self.comb += fifo_in.timestamp.eq(full_ts)
|
|
|
|
self.comb += fifo.we.eq(interface.stb)
|
|
|
|
|
|
|
|
overflow = Signal()
|
|
|
|
self.comb += If(selected, rt_packet.read_overflow.eq(overflow))
|
|
|
|
self.sync.rio += [
|
|
|
|
If(selected & rt_packet.read_overflow_ack, overflow.eq(0)),
|
|
|
|
If(fifo.we & ~fifo.writable, overflow.eq(1))
|
|
|
|
]
|
|
|
|
|
|
|
|
# FIFO read
|
|
|
|
if data_width:
|
|
|
|
self.comb += If(selected, rt_packet.read_data.eq(fifo_out.data))
|
|
|
|
if interface.timestamped:
|
|
|
|
self.comb += If(selected, rt_packet.read_timestamp.eq(fifo_out.timestamp))
|
|
|
|
self.comb += [
|
|
|
|
If(selected,
|
|
|
|
rt_packet.read_readable.eq(fifo.readable),
|
|
|
|
fifo.re.eq(rt_packet.read_consume)
|
|
|
|
)
|
|
|
|
]
|