rtio: refactor, use rtlink

This commit is contained in:
Sebastien Bourdeauducq 2015-04-14 19:44:45 +08:00
parent c0f1708c20
commit 4c10182c9f
16 changed files with 525 additions and 475 deletions

View File

@ -21,17 +21,17 @@ class LLRTIOOut(AutoDB):
@kernel
def _set_oe(self):
syscall("rtio_oe", self.channel, True)
syscall("rtio_set_oe", time_to_cycles(now()), self.channel, True)
@kernel
def set_value(self, t, value):
"""Sets the value of the RTIO channel.
def set_o(self, t, value):
"""Sets the output value of the RTIO channel.
:param t: timestamp in RTIO cycles (64-bit integer).
:param value: value to set at the output.
"""
syscall("rtio_set", t, self.channel, value)
syscall("rtio_set_o", t, self.channel, value)
@kernel
def on(self, t):
@ -40,7 +40,7 @@ class LLRTIOOut(AutoDB):
:param t: timestamp in RTIO cycles (64-bit integer).
"""
self.set_value(t, 1)
self.set_o(t, 1)
@kernel
def off(self, t):
@ -49,28 +49,10 @@ class LLRTIOOut(AutoDB):
:param t: timestamp in RTIO cycles (64-bit integer).
"""
self.set_value(t, 0)
self.set_o(t, 0)
class _RTIOBase(AutoDB):
class DBKeys:
core = Device()
channel = Argument()
def build(self):
self.previous_timestamp = int64(0) # in RTIO cycles
@kernel
def _set_oe(self, oe):
syscall("rtio_oe", self.channel, oe)
@kernel
def _set_value(self, value):
syscall("rtio_set", time_to_cycles(now()), self.channel, value)
self.previous_timestamp = time_to_cycles(now())
class RTIOOut(_RTIOBase):
class RTIOOut(AutoDB):
"""RTIO output driver.
Configures the corresponding RTIO channel as output on the core device and
@ -85,9 +67,22 @@ class RTIOOut(_RTIOBase):
:param channel: channel number
"""
class DBKeys:
core = Device()
channel = Argument()
def build(self):
_RTIOBase.build(self)
self._set_oe(True)
self.previous_timestamp = int64(0) # in RTIO cycles
self._set_oe()
@kernel
def _set_oe(self):
syscall("rtio_set_oe", time_to_cycles(now()), self.channel, True)
@kernel
def _set_o(self, value):
syscall("rtio_set_o", time_to_cycles(now()), self.channel, value)
self.previous_timestamp = time_to_cycles(now())
@kernel
def sync(self):
@ -96,24 +91,19 @@ class RTIOOut(_RTIOBase):
This function is useful to synchronize CPU-controlled devices (such as
the AD9858 DDS bus) with related RTIO controls (such as RF switches at
the output of the DDS).
"""
while syscall("rtio_get_counter") < self.previous_timestamp:
pass
@kernel
def on(self):
"""Sets the output to a logic high state.
"""
self._set_value(1)
"""Sets the output to a logic high state."""
self._set_o(1)
@kernel
def off(self):
"""Sets the output to a logic low state.
"""
self._set_value(0)
"""Sets the output to a logic low state."""
self._set_o(0)
@kernel
def pulse(self, duration):
@ -125,7 +115,7 @@ class RTIOOut(_RTIOBase):
self.off()
class RTIOIn(_RTIOBase):
class RTIOIn(AutoDB):
"""RTIO input driver.
Configures the corresponding RTIO channel as input on the core device and
@ -134,29 +124,41 @@ class RTIOIn(_RTIOBase):
:param core: core device
:param channel: channel number
"""
class DBKeys:
core = Device()
channel = Argument()
def build(self):
_RTIOBase.build(self)
self._set_oe(False)
self.previous_timestamp = int64(0) # in RTIO cycles
self._set_oe()
@kernel
def _set_oe(self):
syscall("rtio_set_oe", time_to_cycles(now()), self.channel, False)
@kernel
def _set_sensitivity(self, value):
syscall("rtio_set_sensitivity", time_to_cycles(now()), self.channel, value)
self.previous_timestamp = time_to_cycles(now())
@kernel
def gate_rising(self, duration):
"""Register rising edge events for the specified duration.
"""
self._set_value(1)
self._set_sensitivity(1)
delay(duration)
self._set_value(0)
self._set_sensitivity(0)
@kernel
def gate_falling(self, duration):
"""Register falling edge events for the specified duration.
"""
self._set_value(2)
self._set_sensitivity(2)
delay(duration)
self._set_value(0)
self._set_sensitivity(0)
@kernel
def gate_both(self, duration):
@ -164,18 +166,9 @@ class RTIOIn(_RTIOBase):
duration.
"""
self._set_value(3)
self._set_sensitivity(3)
delay(duration)
self._set_value(0)
@kernel
def pileup_count(self):
"""Returns the number of pileup events (a system clock cycle with too
many input transitions) since the last call to this function for this
channel (or since the last RTIO reset).
"""
return syscall("rtio_pileup_count", self.channel)
self._set_sensitivity(0)
@kernel
def count(self):

View File

@ -12,11 +12,11 @@ llvm.initialize_all_targets()
llvm.initialize_all_asmprinters()
_syscalls = {
"rtio_oe": "ib:n",
"rtio_set": "Iii:n",
"rtio_set_o": "Iii:n",
"rtio_set_oe": "Iib:n",
"rtio_set_sensitivity": "Iii:n",
"rtio_get_counter": "n:I",
"rtio_get": "iI:I",
"rtio_pileup_count": "i:i",
"dds_phase_clear_en": "ib:n",
"dds_program": "Iiiiibb:n",
}

View File

@ -1,2 +1 @@
from artiq.gateware.rtio import phy
from artiq.gateware.rtio.core import RTIO
from artiq.gateware.rtio.core import Channel, RTIO

View File

@ -2,12 +2,13 @@ from fractions import Fraction
from migen.fhdl.std import *
from migen.bank.description import *
from migen.genlib.misc import optree
from migen.genlib.record import Record
from migen.genlib.cdc import *
from migen.genlib.fifo import AsyncFIFO
from migen.genlib.resetsync import AsyncResetSynchronizer
from artiq.gateware.rtio.rbus import get_fine_ts_width
from artiq.gateware.rtio import rtlink
class _GrayCodeTransfer(Module):
@ -35,26 +36,20 @@ class _GrayCodeTransfer(Module):
class _RTIOCounter(Module):
def __init__(self, width, loopback_latency):
def __init__(self, width):
self.width = width
# Timestamp counter in RTIO domain for outputs
self.o_value_rio = Signal(width)
# Timestamp counter in RTIO domain
self.value_rio = Signal(width)
# Timestamp counter resynchronized to sys domain
# Lags behind o_value_rio, monotonic and glitch-free
self.o_value_sys = Signal(width)
# Timestamp counter in RTIO domain for inputs,
# compensated for PHY loopback latency
self.i_value_rio = Signal(width, reset=2**width-loopback_latency)
# Lags behind value_rio, monotonic and glitch-free
self.value_sys = Signal(width)
# # #
self.sync.rio += [
self.o_value_rio.eq(self.o_value_rio + 1),
self.i_value_rio.eq(self.i_value_rio + 1)
]
self.sync.rio += self.value_rio.eq(self.value_rio + 1),
gt = _GrayCodeTransfer(width)
self.submodules += gt
self.comb += gt.i.eq(self.o_value_rio), self.o_value_sys.eq(gt.o)
self.comb += gt.i.eq(self.value_rio), self.value_sys.eq(gt.o)
# CHOOSING A GUARD TIME
@ -78,263 +73,235 @@ class _RTIOCounter(Module):
# timestamp*Tio > (fifo_depth-1)*Tio + time
# We also have (guard time reached):
# timestamp*Tio < time + guard_io_cycles*Tio
# [NB: time > counter.o_value_sys*Tio]
# [NB: time > counter.value_sys*Tio]
# Thus we must have:
# guard_io_cycles > fifo_depth-1
#
# We can prevent overflows by choosing instead:
# guard_io_cycles < fifo_depth-1
class _RTIOBankO(Module):
def __init__(self, rbus, counter, fine_ts_width, fifo_depth, guard_io_cycles):
self.sel = Signal(max=len(rbus))
# timestamp and value must be valid 1 cycle before we
self.timestamp = Signal(counter.width + fine_ts_width)
self.value = Signal(2)
class _OutputManager(Module):
def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
data_width = rtlink.get_data_width(interface)
address_width = rtlink.get_address_width(interface)
fine_ts_width = rtlink.get_fine_ts_width(interface)
ev_layout = []
if data_width:
ev_layout.append(("data", data_width))
if address_width:
ev_layout.append(("address", address_width))
ev_layout.append(("timestamp", counter.width + fine_ts_width))
# ev must be valid 1 cycle before we to account for the latency in
# generating replace, sequence_error and nop
self.ev = Record(ev_layout)
self.writable = Signal()
self.we = Signal() # maximum throughput 1/2
self.underflow = Signal() # valid 2 cycles after we
self.underflow_reset = Signal()
self.underflow = Signal() # valid 1 cycle after we, pulsed
self.sequence_error = Signal()
self.sequence_error_reset = Signal()
# # #
signal_underflow = Signal()
signal_sequence_error = Signal()
fifos = []
ev_layout = [("timestamp", counter.width + fine_ts_width),
("value", 2)]
for n, chif in enumerate(rbus):
# FIFO
fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth),
{"write": "rsys", "read": "rio"})
self.submodules += fifo
fifos.append(fifo)
# FIFO
fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth),
{"write": "rsys", "read": "rio"})
self.submodules += fifo
# Buffer
buf_pending = Signal()
buf = Record(ev_layout)
buf_just_written = Signal()
# Buffer
buf_pending = Signal()
buf = Record(ev_layout)
buf_just_written = Signal()
# Special cases
replace = Signal()
sequence_error = Signal()
nop = Signal()
self.sync.rsys += [
replace.eq(self.timestamp == buf.timestamp[fine_ts_width:]),
sequence_error.eq(self.timestamp < buf.timestamp[fine_ts_width:]),
nop.eq(self.value == buf.value)
]
self.comb += If(self.we & (self.sel == n) & sequence_error,
signal_sequence_error.eq(1))
# Buffer read and FIFO write
self.comb += fifo.din.eq(buf)
in_guard_time = Signal()
self.comb += in_guard_time.eq(
buf.timestamp[fine_ts_width:] < counter.o_value_sys + guard_io_cycles)
self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
self.comb += \
If(buf_pending,
If(in_guard_time,
If(buf_just_written,
signal_underflow.eq(1)
).Else(
fifo.we.eq(1)
)
),
If((self.we & (self.sel == n)
& ~replace & ~nop & ~sequence_error),
fifo.we.eq(1)
)
)
# Buffer write
# Must come after read to handle concurrent read+write properly
self.sync.rsys += [
buf_just_written.eq(0),
If(self.we & (self.sel == n) & ~nop & ~sequence_error,
buf_just_written.eq(1),
buf_pending.eq(1),
buf.timestamp.eq(self.timestamp),
buf.value.eq(self.value)
)
]
# Buffer output of FIFO to improve timing
dout_stb = Signal()
dout_ack = Signal()
dout = Record(ev_layout)
self.sync.rio += \
If(fifo.re,
dout_stb.eq(1),
dout.eq(fifo.dout)
).Elif(dout_ack,
dout_stb.eq(0)
)
self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))
# FIFO read through buffer
self.comb += [
dout_ack.eq(
dout.timestamp[fine_ts_width:] == counter.o_value_rio),
chif.o_stb.eq(dout_stb & dout_ack),
chif.o_value.eq(dout.value)
]
if fine_ts_width:
self.comb += chif.o_fine_ts.eq(
dout.timestamp[:fine_ts_width])
self.comb += \
self.writable.eq(Array(fifo.writable for fifo in fifos)[self.sel])
# Special cases
replace = Signal()
sequence_error = Signal()
nop = Signal()
self.sync.rsys += [
If(self.underflow_reset, self.underflow.eq(0)),
If(self.sequence_error_reset, self.sequence_error.eq(0)),
If(signal_underflow, self.underflow.eq(1)),
If(signal_sequence_error, self.sequence_error.eq(1))
replace.eq(self.ev.timestamp == buf.timestamp[fine_ts_width:]),
sequence_error.eq(self.ev.timestamp < buf.timestamp[fine_ts_width:])
]
if interface.suppress_nop:
self.sync.rsys += nop.eq(
optree("&",
[getattr(self.ev, a) == getattr(buf, a)
for a in ("data", "address")
if hasattr(self.ev, a)],
default=0))
self.comb += self.sequence_error.eq(self.we & sequence_error)
# Buffer read and FIFO write
self.comb += fifo.din.eq(buf)
in_guard_time = Signal()
self.comb += in_guard_time.eq(
buf.timestamp[fine_ts_width:]
< counter.value_sys + guard_io_cycles)
self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
self.comb += \
If(buf_pending,
If(in_guard_time,
If(buf_just_written,
self.underflow.eq(1)
).Else(
fifo.we.eq(1)
)
),
If(self.we & ~replace & ~nop & ~sequence_error,
fifo.we.eq(1)
)
)
# Buffer write
# Must come after read to handle concurrent read+write properly
self.sync.rsys += [
buf_just_written.eq(0),
If(self.we & ~nop & ~sequence_error,
buf_just_written.eq(1),
buf_pending.eq(1),
buf.eq(self.ev)
)
]
self.comb += self.writable.eq(fifo.writable)
# Buffer output of FIFO to improve timing
dout_stb = Signal()
dout_ack = Signal()
dout = Record(ev_layout)
self.sync.rio += \
If(fifo.re,
dout_stb.eq(1),
dout.eq(fifo.dout)
).Elif(dout_ack,
dout_stb.eq(0)
)
self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))
# FIFO read through buffer
# TODO: report error on stb & busy
self.comb += [
dout_ack.eq(
dout.timestamp[fine_ts_width:] == counter.value_rio),
interface.stb.eq(dout_stb & dout_ack)
]
if data_width:
self.comb += interface.data.eq(dout.data)
if address_width:
self.comb += interface.address.eq(dout.address)
if fine_ts_width:
self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
class _RTIOBankI(Module):
def __init__(self, rbus, counter, fine_ts_width, fifo_depth):
self.sel = Signal(max=len(rbus))
self.timestamp = Signal(counter.width + fine_ts_width)
self.value = Signal()
class _InputManager(Module):
def __init__(self, interface, counter, fifo_depth):
data_width = rtlink.get_data_width(interface)
fine_ts_width = rtlink.get_fine_ts_width(interface)
ev_layout = []
if data_width:
ev_layout.append(("data", data_width))
if interface.timestamped:
ev_layout.append(("timestamp", counter.width + fine_ts_width))
self.ev = Record(ev_layout)
self.readable = Signal()
self.re = Signal()
self.overflow = Signal()
self.overflow_reset = Signal()
self.pileup_count = Signal(16)
self.pileup_reset = Signal()
self.overflow = Signal() # pulsed
# # #
timestamps = []
values = []
readables = []
overflows = []
pileup_counts = []
ev_layout = [("timestamp", counter.width+fine_ts_width),
("value", 1)]
for n, chif in enumerate(rbus):
if hasattr(chif, "oe"):
sensitivity = Signal(2)
self.sync.rio += If(~chif.oe & chif.o_stb,
sensitivity.eq(chif.o_value))
fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth),
{"read": "rsys", "write": "rio"})
self.submodules += fifo
fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth),
{"read": "rsys", "write": "rio"})
self.submodules += fifo
# FIFO write
if fine_ts_width:
full_ts = Cat(chif.i_fine_ts, counter.i_value_rio)
else:
full_ts = counter.i_value_rio
self.comb += [
fifo.din.timestamp.eq(full_ts),
fifo.din.value.eq(chif.i_value),
fifo.we.eq(
~chif.oe & chif.i_stb &
((chif.i_value & sensitivity[0])
| (~chif.i_value & sensitivity[1])))
]
# FIFO read
timestamps.append(fifo.dout.timestamp)
values.append(fifo.dout.value)
readables.append(fifo.readable)
self.comb += fifo.re.eq(self.re & (self.sel == n))
overflow = Signal()
overflow_reset_sync = PulseSynchronizer("rsys", "rio")
self.submodules += overflow_reset_sync
self.comb += overflow_reset_sync.i.eq(
self.overflow_reset & (self.sel == n))
self.sync.rio += [
If(overflow_reset_sync.o, overflow.eq(0)),
If(fifo.we & ~fifo.writable, overflow.eq(1))
]
overflow_sys = Signal()
self.specials += MultiReg(overflow, overflow_sys, "rsys")
overflows.append(overflow_sys)
pileup_count = Signal(16)
pileup_count_reset_sync = PulseSynchronizer("rsys", "rio")
self.submodules += pileup_count_reset_sync
self.comb += pileup_count_reset_sync.i.eq(
self.pileup_reset & (self.sel == n))
self.sync.rio += \
If(pileup_count_reset_sync.o,
pileup_count.eq(0)
).Elif(chif.i_pileup,
If(pileup_count != 2**16 - 1, # saturate
pileup_count.eq(pileup_count + 1)
)
)
pileup_count_sync = _GrayCodeTransfer(16)
self.submodules += pileup_count_sync
self.comb += pileup_count_sync.i.eq(pileup_count)
pileup_counts.append(pileup_count_sync.o)
# FIFO write
if data_width:
self.comb += fifo.din.data.eq(interface.data)
if interface.timestamped:
if fine_ts_width:
full_ts = Cat(interface.fine_ts, counter.value_rio)
else:
timestamps.append(0)
values.append(0)
readables.append(0)
overflows.append(0)
pileup_counts.append(0)
full_ts = counter.value_rio
self.comb += fifo.din.timestamp.eq(full_ts)
self.comb += fifo.we.eq(interface.stb)
# FIFO read
self.comb += [
self.timestamp.eq(Array(timestamps)[self.sel]),
self.value.eq(Array(values)[self.sel]),
self.readable.eq(Array(readables)[self.sel]),
self.overflow.eq(Array(overflows)[self.sel]),
self.pileup_count.eq(Array(pileup_counts)[self.sel])
self.ev.eq(fifo.dout),
self.readable.eq(fifo.readable),
fifo.re.eq(self.re)
]
overflow_sync = PulseSynchronizer("rio", "rsys")
overflow_ack_sync = PulseSynchronizer("rsys", "rio")
self.submodules += overflow_sync, overflow_ack_sync
overflow_blind = Signal()
self.comb += overflow_sync.i.eq(fifo.we & ~fifo.writable & ~overflow_blind)
self.sync.rio += [
If(fifo.we & ~fifo.writable, overflow_blind.eq(1)),
If(overflow_ack_sync.o, overflow_blind.eq(0))
]
self.comb += [
overflow_ack_sync.i.eq(overflow_sync.o),
self.overflow.eq(overflow_sync.o)
]
class RTIO(Module, AutoCSR):
def __init__(self, phy, clk_freq, counter_width=63,
ofifo_depth=64, ififo_depth=64,
guard_io_cycles=20):
fine_ts_width = get_fine_ts_width(phy.rbus)
class Channel:
def __init__(self, interface, ofifo_depth=64, ififo_depth=64):
self.interface = interface
self.ofifo_depth = ofifo_depth
self.ififo_depth = ififo_depth
# Submodules
self.submodules.counter = _RTIOCounter(
counter_width, phy.loopback_latency)
self.submodules.bank_o = _RTIOBankO(
phy.rbus, self.counter, fine_ts_width, ofifo_depth, guard_io_cycles)
self.submodules.bank_i = _RTIOBankI(
phy.rbus, self.counter, fine_ts_width, ififo_depth)
class _CSRs(AutoCSR):
def __init__(self):
self.frequency_i = CSRStatus(32)
self.frequency_fn = CSRStatus(8)
self.frequency_fd = CSRStatus(8)
class _KernelCSRs(AutoCSR):
def __init__(self, chan_sel_width,
data_width, address_width, full_ts_width):
self.reset = CSRStorage(reset=1)
self.chan_sel = CSRStorage(chan_sel_width)
self.o_data = CSRStorage(data_width)
self.o_address = CSRStorage(address_width)
self.o_timestamp = CSRStorage(full_ts_width)
self.o_we = CSR()
self.o_status = CSRStatus(3)
self.o_underflow_reset = CSR()
self.o_sequence_error_reset = CSR()
self.i_data = CSRStatus(data_width)
self.i_timestamp = CSRStatus(full_ts_width)
self.i_re = CSR()
self.i_status = CSRStatus(2)
self.i_overflow_reset = CSR()
self.counter = CSRStatus(full_ts_width)
self.counter_update = CSR()
class RTIO(Module):
def __init__(self, channels, clk_freq, counter_width=63,
guard_io_cycles=20):
data_width = max(rtlink.get_data_width(c.interface)
for c in channels)
address_width = max(rtlink.get_address_width(c.interface)
for c in channels)
fine_ts_width = max(rtlink.get_fine_ts_width(c.interface)
for c in channels)
# CSRs
self._reset = CSRStorage(reset=1)
self._chan_sel = CSRStorage(flen(self.bank_o.sel))
self._oe = CSR()
self._o_timestamp = CSRStorage(counter_width + fine_ts_width)
self._o_value = CSRStorage(2)
self._o_we = CSR()
self._o_status = CSRStatus(3)
self._o_underflow_reset = CSR()
self._o_sequence_error_reset = CSR()
self._i_timestamp = CSRStatus(counter_width + fine_ts_width)
self._i_value = CSRStatus()
self._i_re = CSR()
self._i_status = CSRStatus(2)
self._i_overflow_reset = CSR()
self._i_pileup_count = CSRStatus(16)
self._i_pileup_reset = CSR()
self._counter = CSRStatus(counter_width + fine_ts_width)
self._counter_update = CSR()
self._frequency_i = CSRStatus(32)
self._frequency_fn = CSRStatus(8)
self._frequency_fd = CSRStatus(8)
self.csrs = _CSRs()
self.kcsrs = _KernelCSRs(bits_for(len(channels)-1),
max(data_width, 1),
max(address_width, 1),
counter_width + fine_ts_width)
# Clocking/Reset
# Create rsys and rio domains based on sys and rio
@ -343,63 +310,113 @@ class RTIO(Module, AutoCSR):
self.clock_domains.cd_rio = ClockDomain()
self.comb += [
self.cd_rsys.clk.eq(ClockSignal()),
self.cd_rsys.rst.eq(self._reset.storage)
self.cd_rsys.rst.eq(self.kcsrs.reset.storage)
]
self.comb += self.cd_rio.clk.eq(ClockSignal("rtio"))
self.specials += AsyncResetSynchronizer(
self.cd_rio, self._reset.storage)
self.specials += AsyncResetSynchronizer(self.cd_rio,
self.kcsrs.reset.storage)
# Latency compensation
# TODO
# Managers
self.submodules.counter = _RTIOCounter(counter_width)
i_datas, i_timestamps = [], []
o_statuses, i_statuses = [], []
sel = self.kcsrs.chan_sel.storage
for n, channel in enumerate(channels):
selected = Signal()
self.comb += selected.eq(sel == n)
o_manager = _OutputManager(channel.interface.o, self.counter,
channel.ofifo_depth, guard_io_cycles)
self.submodules += o_manager
if hasattr(o_manager.ev, "data"):
self.comb += o_manager.ev.data.eq(
self.kcsrs.o_data.storage)
if hasattr(o_manager.ev, "address"):
self.comb += o_manager.ev.address.eq(
self.kcsrs.o_address.storage)
ts_shift = (flen(self.kcsrs.o_timestamp.storage)
- flen(o_manager.ev.timestamp))
self.comb += o_manager.ev.timestamp.eq(
self.kcsrs.o_timestamp.storage[ts_shift:])
self.comb += o_manager.we.eq(selected & self.kcsrs.o_we.re)
underflow = Signal()
sequence_error = Signal()
self.sync.rsys += [
If(selected & self.kcsrs.o_underflow_reset.re,
underflow.eq(0)),
If(selected & self.kcsrs.o_sequence_error_reset.re,
sequence_error.eq(0)),
If(o_manager.underflow, underflow.eq(1)),
If(o_manager.sequence_error, sequence_error.eq(1))
]
o_statuses.append(Cat(~o_manager.writable,
underflow,
sequence_error))
if channel.interface.i is not None:
i_manager = _InputManager(channel.interface.i, self.counter,
channel.ififo_depth)
self.submodules += i_manager
if hasattr(i_manager.ev, "data"):
i_datas.append(i_manager.ev.data)
else:
i_datas.append(0)
if channel.interface.i.timestamped:
ts_shift = (flen(self.kcsrs.i_timestamp.status)
- flen(i_manager.ev.timestamp))
i_timestamps.append(i_manager.ev.timestamp << ts_shift)
else:
i_timestamps.append(0)
self.comb += i_manager.re.eq(selected & self.kcsrs.i_re.re)
overflow = Signal()
self.sync.rsys += [
If(selected & self.kcsrs.i_overflow_reset.re,
overflow.eq(0)),
If(i_manager.overflow,
overflow.eq(1))
]
i_statuses.append(Cat(~i_manager.readable, overflow))
# OE
oes = []
for n, chif in enumerate(phy.rbus):
if hasattr(chif, "oe"):
self.sync += \
If(self._oe.re & (self._chan_sel.storage == n),
chif.oe.eq(self._oe.r)
)
oes.append(chif.oe)
else:
oes.append(1)
self.comb += self._oe.w.eq(Array(oes)[self._chan_sel.storage])
# Output/Gate
i_datas.append(0)
i_timestamps.append(0)
i_statuses.append(0)
self.comb += [
self.bank_o.sel.eq(self._chan_sel.storage),
self.bank_o.timestamp.eq(self._o_timestamp.storage),
self.bank_o.value.eq(self._o_value.storage),
self.bank_o.we.eq(self._o_we.re),
self._o_status.status.eq(Cat(~self.bank_o.writable,
self.bank_o.underflow,
self.bank_o.sequence_error)),
self.bank_o.underflow_reset.eq(self._o_underflow_reset.re),
self.bank_o.sequence_error_reset.eq(self._o_sequence_error_reset.re)
]
# Input
self.comb += [
self.bank_i.sel.eq(self._chan_sel.storage),
self._i_timestamp.status.eq(self.bank_i.timestamp),
self._i_value.status.eq(self.bank_i.value),
self.bank_i.re.eq(self._i_re.re),
self._i_status.status.eq(Cat(~self.bank_i.readable, self.bank_i.overflow)),
self.bank_i.overflow_reset.eq(self._i_overflow_reset.re),
self._i_pileup_count.status.eq(self.bank_i.pileup_count),
self.bank_i.pileup_reset.eq(self._i_pileup_reset.re)
self.kcsrs.i_data.status.eq(Array(i_datas)[sel]),
self.kcsrs.i_timestamp.status.eq(Array(i_timestamps)[sel]),
self.kcsrs.o_status.status.eq(Array(o_statuses)[sel]),
self.kcsrs.i_status.status.eq(Array(i_statuses)[sel])
]
# Counter access
self.sync += \
If(self._counter_update.re,
self._counter.status.eq(Cat(Replicate(0, fine_ts_width),
self.counter.o_value_sys))
If(self.kcsrs.counter_update.re,
self.kcsrs.counter.status.eq(self.counter.value_sys
<< fine_ts_width)
)
# Frequency
# Frequency CSRs
clk_freq = Fraction(clk_freq).limit_denominator(255)
clk_freq_i = int(clk_freq)
clk_freq_f = clk_freq - clk_freq_i
self.comb += [
self._frequency_i.status.eq(clk_freq_i),
self._frequency_fn.status.eq(clk_freq_f.numerator),
self._frequency_fd.status.eq(clk_freq_f.denominator)
self.csrs.frequency_i.status.eq(clk_freq_i),
self.csrs.frequency_fn.status.eq(clk_freq_f.numerator),
self.csrs.frequency_fd.status.eq(clk_freq_f.denominator)
]
def get_csrs(self):
return self.csrs.get_csrs()
def get_kernel_csrs(self):
return self.kcsrs.get_csrs()

View File

@ -1,30 +0,0 @@
from migen.fhdl.std import *
from migen.genlib.cdc import MultiReg
from artiq.gateware.rtio.rbus import create_rbus
class SimplePHY(Module):
def __init__(self, pads, output_only_pads=set()):
self.rbus = create_rbus(0, pads, output_only_pads)
self.loopback_latency = 3
# # #
for pad, chif in zip(pads, self.rbus):
o_pad = Signal()
self.sync.rio += If(chif.o_stb, o_pad.eq(chif.o_value))
if hasattr(chif, "oe"):
ts = TSTriple()
i_pad = Signal()
self.sync.rio += ts.oe.eq(chif.oe)
self.comb += ts.o.eq(o_pad)
self.specials += MultiReg(ts.i, i_pad, "rio"), \
ts.get_tristate(pad)
i_pad_d = Signal()
self.sync.rio += i_pad_d.eq(i_pad)
self.comb += chif.i_stb.eq(i_pad ^ i_pad_d), \
chif.i_value.eq(i_pad)
else:
self.comb += pad.eq(o_pad)

View File

View File

@ -0,0 +1,46 @@
from migen.fhdl.std import *
from migen.genlib.cdc import MultiReg
from artiq.gateware.rtio import rtlink
class Output(Module):
def __init__(self, pad):
self.rtlink = rtlink.Interface(rtlink.OInterface(1))
# # #
self.sync.rio += If(self.rtlink.o.stb, pad.eq(self.rtlink.o.data))
class Inout(Module):
def __init__(self, pad):
self.rtlink = rtlink.Interface(
rtlink.OInterface(2, 2),
rtlink.IInterface(1))
# # #
ts = TSTriple()
self.specials += ts.get_tristate(pad)
sensitivity = Signal(2)
self.sync.rio += If(self.rtlink.o.stb,
Case(self.rtlink.o.address, {
0: ts.o.eq(self.rtlink.o.data[0]),
1: ts.oe.eq(self.rtlink.o.data[0]),
2: sensitivity.eq(self.rtlink.o.data)
}).makedefault()
)
i = Signal()
i_d = Signal()
self.specials += MultiReg(ts.i, i, "rio")
self.sync.rio += i_d.eq(i)
self.comb += [
self.rtlink.i.stb.eq(
(sensitivity[0] & ( i & ~i_d)) |
(sensitivity[1] & (~i & i_d))
),
self.rtlink.i.data.eq(i)
]

View File

@ -1,31 +0,0 @@
from migen.fhdl.std import *
from migen.genlib.record import Record
def create_rbus(fine_ts_bits, pads, output_only_pads):
rbus = []
for pad in pads:
layout = [
("o_stb", 1),
("o_value", 2)
]
if fine_ts_bits:
layout.append(("o_fine_ts", fine_ts_bits))
if pad not in output_only_pads:
layout += [
("oe", 1),
("i_stb", 1),
("i_value", 1),
("i_pileup", 1)
]
if fine_ts_bits:
layout.append(("i_fine_ts", fine_ts_bits))
rbus.append(Record(layout))
return rbus
def get_fine_ts_width(rbus):
if hasattr(rbus[0], "o_fine_ts"):
return flen(rbus[0].o_fine_ts)
else:
return 0

View File

@ -54,7 +54,7 @@ ksupport.elf: $(OBJECTS_KSUPPORT)
ksupport_data.o: ksupport.bin
$(LD) -r -b binary -o $@ $<
service_table.h: $(SERVICE_TABLE_INPUT)
service_table.h: $(SERVICE_TABLE_INPUT) gen_service_table.py
@echo " GEN " $@ && ./gen_service_table.py $(SERVICE_TABLE_INPUT) > $@
services.c: service_table.h

View File

@ -6,11 +6,11 @@ import sys
services = [
("syscalls", [
("rpc", "comm_rpc"),
("rtio_oe", "rtio_oe"),
("rtio_set", "rtio_set"),
("rtio_set_o", "rtio_set_o"),
("rtio_set_oe", "rtio_set_oe"),
("rtio_set_sensitivity", "rtio_set_sensitivity"),
("rtio_get_counter", "rtio_get_counter"),
("rtio_get", "rtio_get"),
("rtio_pileup_count", "rtio_pileup_count"),
("dds_phase_clear_en", "dds_phase_clear_en"),
("dds_program", "dds_program"),
]),

View File

@ -18,19 +18,10 @@ void rtio_init(void)
rtio_reset_write(0);
}
void rtio_oe(int channel, int oe)
{
rtio_chan_sel_write(channel);
rtio_oe_write(oe);
}
void rtio_set(long long int timestamp, int channel, int value)
static void write_and_process_status(long long int timestamp, int channel)
{
int status;
rtio_chan_sel_write(channel);
rtio_o_timestamp_write(timestamp);
rtio_o_value_write(value);
rtio_o_we_write(1);
status = rtio_o_status_read();
if(status) {
@ -49,6 +40,33 @@ void rtio_set(long long int timestamp, int channel, int value)
}
}
void rtio_set_o(long long int timestamp, int channel, int value)
{
rtio_chan_sel_write(channel);
rtio_o_timestamp_write(timestamp);
rtio_o_address_write(0);
rtio_o_data_write(value);
write_and_process_status(timestamp, channel);
}
void rtio_set_oe(long long int timestamp, int channel, int oe)
{
rtio_chan_sel_write(channel);
rtio_o_timestamp_write(timestamp);
rtio_o_address_write(1);
rtio_o_data_write(oe);
write_and_process_status(timestamp, channel);
}
void rtio_set_sensitivity(long long int timestamp, int channel, int sensitivity)
{
rtio_chan_sel_write(channel);
rtio_o_timestamp_write(timestamp);
rtio_o_address_write(2);
rtio_o_data_write(sensitivity);
write_and_process_status(timestamp, channel);
}
long long int rtio_get_counter(void)
{
rtio_counter_update_write(1);
@ -81,16 +99,6 @@ long long int rtio_get(int channel, long long int time_limit)
return r;
}
int rtio_pileup_count(int channel)
{
int r;
rtio_chan_sel_write(channel);
r = rtio_i_pileup_count_read();
rtio_i_pileup_reset_write(1);
return r;
}
void rtio_fud_sync(void)
{
while(rtio_get_counter() < previous_fud_end_time);
@ -102,14 +110,15 @@ void rtio_fud(long long int fud_time)
int status;
rtio_chan_sel_write(RTIO_FUD_CHANNEL);
rtio_o_address_write(0);
fud_end_time = fud_time + 3*8;
previous_fud_end_time = fud_end_time;
rtio_o_timestamp_write(fud_time);
rtio_o_value_write(1);
rtio_o_data_write(1);
rtio_o_we_write(1);
rtio_o_timestamp_write(fud_end_time);
rtio_o_value_write(0);
rtio_o_data_write(0);
rtio_o_we_write(1);
status = rtio_o_status_read();
if(status) {

View File

@ -2,11 +2,11 @@
#define __RTIO_H
void rtio_init(void);
void rtio_oe(int channel, int oe);
void rtio_set(long long int timestamp, int channel, int value);
void rtio_set_o(long long int timestamp, int channel, int value);
void rtio_set_oe(long long int timestamp, int channel, int oe);
void rtio_set_sensitivity(long long int timestamp, int channel, int sensitivity);
long long int rtio_get_counter(void);
long long int rtio_get(int channel, long long int time_limit);
int rtio_pileup_count(int channel);
void rtio_fud_sync(void);
void rtio_fud(long long int fud_time);

View File

@ -82,8 +82,8 @@ static void ttlout(char *n, char *value)
}
rtio_init();
rtio_oe(n2, 1);
rtio_set(rtio_get_counter() + 8000, n2, value2);
rtio_set_oe(rtio_get_counter() + 8000, n2, 1);
rtio_set_o(rtio_get_counter() + 8000, n2, value2);
}
static void ddssel(char *n)

View File

@ -9,6 +9,7 @@ from misoclib.soc import mem_decoder
from targets.kc705 import MiniSoC
from artiq.gateware import amp, rtio, ad9858, nist_qc1
from artiq.gateware.rtio.phy import ttl_simple
class _RTIOCRG(Module, AutoCSR):
@ -50,24 +51,36 @@ class _Peripherals(MiniSoC):
platform.request("user_led", 0),
platform.request("user_led", 1)))
fud = Signal()
self.comb += [
platform.request("ttl_l_tx_en").eq(1),
platform.request("ttl_h_tx_en").eq(1)
]
rtio_ins = [platform.request("pmt") for i in range(2)]
rtio_outs = [platform.request("ttl", i) for i in range(16)]
rtio_outs.append(platform.request("user_led", 2))
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_ins) + len(rtio_outs))
rtio_outs.append(fud)
# RTIO channels
rtio_channels = []
for i in range(2):
phy = ttl_simple.Inout(platform.request("pmt", i))
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=512))
for i in range(16):
phy = ttl_simple.Output(platform.request("ttl", i))
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
phy = ttl_simple.Output(platform.request("user_led", 2))
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
fud = Signal()
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels))
phy = ttl_simple.Output(fud)
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
# RTIO core
self.submodules.rtiocrg = _RTIOCRG(platform, self.crg.pll_sys)
self.submodules.rtiophy = rtio.phy.SimplePHY(
rtio_ins + rtio_outs,
output_only_pads=set(rtio_outs))
self.submodules.rtio = rtio.RTIO(self.rtiophy,
clk_freq=125000000,
ififo_depth=512)
self.submodules.rtio = rtio.RTIO(rtio_channels,
clk_freq=125000000)
dds_pads = platform.request("dds")
self.submodules.dds = ad9858.AD9858(dds_pads)
@ -85,7 +98,7 @@ class UP(_Peripherals):
def __init__(self, *args, **kwargs):
_Peripherals.__init__(self, *args, **kwargs)
rtio_csrs = self.rtio.get_csrs()
rtio_csrs = self.rtio.get_csrs() + self.rtio.get_kernel_csrs()
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
self.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus)
self.add_csr_region("rtio", self.mem_map["rtio"] + 0x80000000, 32, rtio_csrs)
@ -93,6 +106,7 @@ class UP(_Peripherals):
self.add_wb_slave(mem_decoder(self.mem_map["dds"]), self.dds.bus)
self.add_memory_region("dds", self.mem_map["dds"] + 0x80000000, 64*4)
class AMP(_Peripherals):
csr_map = {
"kernel_cpu": 14
@ -112,7 +126,7 @@ class AMP(_Peripherals):
self.add_wb_slave(mem_decoder(self.mem_map["mailbox"]), self.mailbox.i1)
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["mailbox"]), self.mailbox.i2)
rtio_csrs = self.rtio.get_csrs()
rtio_csrs = self.rtio.get_kernel_csrs()
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus)
self.add_csr_region("rtio", self.mem_map["rtio"] + 0x80000000, 32, rtio_csrs)
@ -120,4 +134,5 @@ class AMP(_Peripherals):
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["dds"]), self.dds.bus)
self.add_memory_region("dds", self.mem_map["dds"] + 0x80000000, 64*4)
default_subtarget = AMP

View File

@ -7,6 +7,7 @@ from misoclib.soc import mem_decoder
from targets.pipistrello import BaseSoC
from artiq.gateware import amp, rtio, ad9858, nist_qc1
from artiq.gateware.rtio.phy import ttl_simple
class _RTIOCRG(Module, AutoCSR):
@ -66,26 +67,46 @@ class _Peripherals(BaseSoC):
platform.request("user_led", 1),
))
fud = Signal()
self.comb += [
platform.request("ttl_l_tx_en").eq(1),
platform.request("ttl_h_tx_en").eq(1)
]
rtio_ins = [platform.request("pmt", i) for i in range(2)]
rtio_ins += [platform.request("xtrig", 0)]
rtio_outs = [platform.request("ttl", i) for i in range(16)]
rtio_outs += [platform.request("ext_led", 0)]
rtio_outs += [platform.request("user_led", i) for i in range(2, 5)]
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_ins) + len(rtio_outs))
rtio_outs.append(fud)
# RTIO channels
rtio_channels = []
for i in range(2):
phy = ttl_simple.Inout(platform.request("pmt", i))
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=512))
phy = ttl_simple.Inout(platform.request("xtrig", 0))
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
for i in range(16):
phy = ttl_simple.Output(platform.request("ttl", i))
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
phy = ttl_simple.Output(platform.request("ext_led", 0))
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
for i in range(2, 5):
phy = ttl_simple.Output(platform.request("user_led", i))
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
fud = Signal()
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels))
phy = ttl_simple.Output(fud)
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
# RTIO core
self.submodules.rtiocrg = _RTIOCRG(platform)
self.submodules.rtiophy = rtio.phy.SimplePHY(
rtio_ins + rtio_outs,
output_only_pads=set(rtio_outs))
self.submodules.rtio = rtio.RTIO(self.rtiophy,
clk_freq=125000000,
ififo_depth=512)
self.submodules.rtio = rtio.RTIO(rtio_channels,
clk_freq=125000000)
dds_pads = platform.request("dds")
self.submodules.dds = ad9858.AD9858(dds_pads)

View File

@ -9,6 +9,7 @@ from misoclib.mem.sdram.core.minicon import MiniconSettings
from targets.ppro import BaseSoC
from artiq.gateware import rtio, ad9858, nist_qc1
from artiq.gateware.rtio.phy import ttl_simple
class _TestGen(Module):
@ -78,29 +79,39 @@ class UP(BaseSoC):
platform.request("user_led", 0),
platform.request("ext_led", 0)))
fud = Signal()
self.comb += [
platform.request("ttl_l_tx_en").eq(1),
platform.request("ttl_h_tx_en").eq(1)
]
rtio_ins = [platform.request("pmt") for i in range(2)]
rtio_outs = [platform.request("ttl", i) for i in range(5)]
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_ins) + len(rtio_outs))
rtio_outs.append(fud)
# RTIO channels
rtio_channels = []
for i in range(2):
phy = ttl_simple.Inout(platform.request("pmt", i))
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
for i in range(5):
phy = ttl_simple.Output(platform.request("ttl", i))
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
fud = Signal()
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels))
phy = ttl_simple.Output(fud)
self.submodules += phy
rtio_channels.append(rtio.Channel(phy.rtlink))
# RTIO core
self.submodules.rtiocrg = _RTIOMiniCRG(platform)
self.submodules.rtiophy = rtio.phy.SimplePHY(
rtio_ins + rtio_outs,
output_only_pads=set(rtio_outs))
self.submodules.rtio = rtio.RTIO(self.rtiophy,
self.submodules.rtio = rtio.RTIO(rtio_channels,
clk_freq=125000000,
counter_width=32,
ififo_depth=512)
counter_width=32)
rtio_csrs = self.rtio.get_csrs()
rtio_csrs = self.rtio.get_csrs() + self.rtio.get_kernel_csrs()
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
self.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus)
self.add_csr_region("rtio", self.mem_map["rtio"] + 0x80000000, 32, rtio_csrs)
self.add_csr_region("rtio", self.mem_map["rtio"] + 0x80000000,
32, rtio_csrs)
if with_test_gen:
self.submodules.test_gen = _TestGen(platform.request("ttl", 8))