forked from M-Labs/artiq
1
0
Fork 0

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

View File

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

View File

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

View File

@ -2,12 +2,13 @@ from fractions import Fraction
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.bank.description import * from migen.bank.description import *
from migen.genlib.misc import optree
from migen.genlib.record import Record from migen.genlib.record import Record
from migen.genlib.cdc import * from migen.genlib.cdc import *
from migen.genlib.fifo import AsyncFIFO from migen.genlib.fifo import AsyncFIFO
from migen.genlib.resetsync import AsyncResetSynchronizer 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): class _GrayCodeTransfer(Module):
@ -35,26 +36,20 @@ class _GrayCodeTransfer(Module):
class _RTIOCounter(Module): class _RTIOCounter(Module):
def __init__(self, width, loopback_latency): def __init__(self, width):
self.width = width self.width = width
# Timestamp counter in RTIO domain for outputs # Timestamp counter in RTIO domain
self.o_value_rio = Signal(width) self.value_rio = Signal(width)
# Timestamp counter resynchronized to sys domain # Timestamp counter resynchronized to sys domain
# Lags behind o_value_rio, monotonic and glitch-free # Lags behind value_rio, monotonic and glitch-free
self.o_value_sys = Signal(width) self.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)
# # # # # #
self.sync.rio += [ self.sync.rio += self.value_rio.eq(self.value_rio + 1),
self.o_value_rio.eq(self.o_value_rio + 1),
self.i_value_rio.eq(self.i_value_rio + 1)
]
gt = _GrayCodeTransfer(width) gt = _GrayCodeTransfer(width)
self.submodules += gt 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 # CHOOSING A GUARD TIME
@ -78,263 +73,235 @@ class _RTIOCounter(Module):
# timestamp*Tio > (fifo_depth-1)*Tio + time # timestamp*Tio > (fifo_depth-1)*Tio + time
# We also have (guard time reached): # We also have (guard time reached):
# timestamp*Tio < time + guard_io_cycles*Tio # timestamp*Tio < time + guard_io_cycles*Tio
# [NB: time > counter.o_value_sys*Tio] # [NB: time > counter.value_sys*Tio]
# Thus we must have: # Thus we must have:
# guard_io_cycles > fifo_depth-1 # guard_io_cycles > fifo_depth-1
# #
# We can prevent overflows by choosing instead: # We can prevent overflows by choosing instead:
# guard_io_cycles < fifo_depth-1 # guard_io_cycles < fifo_depth-1
class _RTIOBankO(Module): class _OutputManager(Module):
def __init__(self, rbus, counter, fine_ts_width, fifo_depth, guard_io_cycles): def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
self.sel = Signal(max=len(rbus)) data_width = rtlink.get_data_width(interface)
# timestamp and value must be valid 1 cycle before we address_width = rtlink.get_address_width(interface)
self.timestamp = Signal(counter.width + fine_ts_width) fine_ts_width = rtlink.get_fine_ts_width(interface)
self.value = Signal(2)
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.writable = Signal()
self.we = Signal() # maximum throughput 1/2 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 = Signal()
self.sequence_error_reset = Signal()
# # # # # #
signal_underflow = Signal() # FIFO
signal_sequence_error = Signal() fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth),
fifos = [] {"write": "rsys", "read": "rio"})
ev_layout = [("timestamp", counter.width + fine_ts_width), self.submodules += fifo
("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)
# Buffer # Buffer
buf_pending = Signal() buf_pending = Signal()
buf = Record(ev_layout) buf = Record(ev_layout)
buf_just_written = Signal() buf_just_written = Signal()
# Special cases # Special cases
replace = Signal() replace = Signal()
sequence_error = Signal() sequence_error = Signal()
nop = 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])
self.sync.rsys += [ self.sync.rsys += [
If(self.underflow_reset, self.underflow.eq(0)), replace.eq(self.ev.timestamp == buf.timestamp[fine_ts_width:]),
If(self.sequence_error_reset, self.sequence_error.eq(0)), sequence_error.eq(self.ev.timestamp < buf.timestamp[fine_ts_width:])
If(signal_underflow, self.underflow.eq(1)),
If(signal_sequence_error, self.sequence_error.eq(1))
] ]
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): class _InputManager(Module):
def __init__(self, rbus, counter, fine_ts_width, fifo_depth): def __init__(self, interface, counter, fifo_depth):
self.sel = Signal(max=len(rbus)) data_width = rtlink.get_data_width(interface)
self.timestamp = Signal(counter.width + fine_ts_width) fine_ts_width = rtlink.get_fine_ts_width(interface)
self.value = Signal()
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.readable = Signal()
self.re = Signal() self.re = Signal()
self.overflow = Signal()
self.overflow_reset = Signal() self.overflow = Signal() # pulsed
self.pileup_count = Signal(16)
self.pileup_reset = Signal()
# # # # # #
timestamps = [] fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth),
values = [] {"read": "rsys", "write": "rio"})
readables = [] self.submodules += fifo
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), # FIFO write
{"read": "rsys", "write": "rio"}) if data_width:
self.submodules += fifo self.comb += fifo.din.data.eq(interface.data)
if interface.timestamped:
# FIFO write if fine_ts_width:
if fine_ts_width: full_ts = Cat(interface.fine_ts, counter.value_rio)
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)
else: else:
timestamps.append(0) full_ts = counter.value_rio
values.append(0) self.comb += fifo.din.timestamp.eq(full_ts)
readables.append(0) self.comb += fifo.we.eq(interface.stb)
overflows.append(0)
pileup_counts.append(0)
# FIFO read
self.comb += [ self.comb += [
self.timestamp.eq(Array(timestamps)[self.sel]), self.ev.eq(fifo.dout),
self.value.eq(Array(values)[self.sel]), self.readable.eq(fifo.readable),
self.readable.eq(Array(readables)[self.sel]), fifo.re.eq(self.re)
self.overflow.eq(Array(overflows)[self.sel]), ]
self.pileup_count.eq(Array(pileup_counts)[self.sel])
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): class Channel:
def __init__(self, phy, clk_freq, counter_width=63, def __init__(self, interface, ofifo_depth=64, ififo_depth=64):
ofifo_depth=64, ififo_depth=64, self.interface = interface
guard_io_cycles=20): self.ofifo_depth = ofifo_depth
fine_ts_width = get_fine_ts_width(phy.rbus) self.ififo_depth = ififo_depth
# Submodules
self.submodules.counter = _RTIOCounter( class _CSRs(AutoCSR):
counter_width, phy.loopback_latency) def __init__(self):
self.submodules.bank_o = _RTIOBankO( self.frequency_i = CSRStatus(32)
phy.rbus, self.counter, fine_ts_width, ofifo_depth, guard_io_cycles) self.frequency_fn = CSRStatus(8)
self.submodules.bank_i = _RTIOBankI( self.frequency_fd = CSRStatus(8)
phy.rbus, self.counter, fine_ts_width, ififo_depth)
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 # CSRs
self._reset = CSRStorage(reset=1) self.csrs = _CSRs()
self._chan_sel = CSRStorage(flen(self.bank_o.sel)) self.kcsrs = _KernelCSRs(bits_for(len(channels)-1),
max(data_width, 1),
self._oe = CSR() max(address_width, 1),
counter_width + fine_ts_width)
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)
# Clocking/Reset # Clocking/Reset
# Create rsys and rio domains based on sys and rio # 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.clock_domains.cd_rio = ClockDomain()
self.comb += [ self.comb += [
self.cd_rsys.clk.eq(ClockSignal()), 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.comb += self.cd_rio.clk.eq(ClockSignal("rtio"))
self.specials += AsyncResetSynchronizer( self.specials += AsyncResetSynchronizer(self.cd_rio,
self.cd_rio, self._reset.storage) 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: else:
oes.append(1) i_datas.append(0)
self.comb += self._oe.w.eq(Array(oes)[self._chan_sel.storage]) i_timestamps.append(0)
i_statuses.append(0)
# Output/Gate
self.comb += [ self.comb += [
self.bank_o.sel.eq(self._chan_sel.storage), self.kcsrs.i_data.status.eq(Array(i_datas)[sel]),
self.bank_o.timestamp.eq(self._o_timestamp.storage), self.kcsrs.i_timestamp.status.eq(Array(i_timestamps)[sel]),
self.bank_o.value.eq(self._o_value.storage), self.kcsrs.o_status.status.eq(Array(o_statuses)[sel]),
self.bank_o.we.eq(self._o_we.re), self.kcsrs.i_status.status.eq(Array(i_statuses)[sel])
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)
] ]
# Counter access # Counter access
self.sync += \ self.sync += \
If(self._counter_update.re, If(self.kcsrs.counter_update.re,
self._counter.status.eq(Cat(Replicate(0, fine_ts_width), self.kcsrs.counter.status.eq(self.counter.value_sys
self.counter.o_value_sys)) << fine_ts_width)
) )
# Frequency # Frequency CSRs
clk_freq = Fraction(clk_freq).limit_denominator(255) clk_freq = Fraction(clk_freq).limit_denominator(255)
clk_freq_i = int(clk_freq) clk_freq_i = int(clk_freq)
clk_freq_f = clk_freq - clk_freq_i clk_freq_f = clk_freq - clk_freq_i
self.comb += [ self.comb += [
self._frequency_i.status.eq(clk_freq_i), self.csrs.frequency_i.status.eq(clk_freq_i),
self._frequency_fn.status.eq(clk_freq_f.numerator), self.csrs.frequency_fn.status.eq(clk_freq_f.numerator),
self._frequency_fd.status.eq(clk_freq_f.denominator) 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 ksupport_data.o: ksupport.bin
$(LD) -r -b binary -o $@ $< $(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) > $@ @echo " GEN " $@ && ./gen_service_table.py $(SERVICE_TABLE_INPUT) > $@
services.c: service_table.h services.c: service_table.h

View File

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

View File

@ -18,19 +18,10 @@ void rtio_init(void)
rtio_reset_write(0); rtio_reset_write(0);
} }
void rtio_oe(int channel, int oe) static void write_and_process_status(long long int timestamp, int channel)
{
rtio_chan_sel_write(channel);
rtio_oe_write(oe);
}
void rtio_set(long long int timestamp, int channel, int value)
{ {
int status; int status;
rtio_chan_sel_write(channel);
rtio_o_timestamp_write(timestamp);
rtio_o_value_write(value);
rtio_o_we_write(1); rtio_o_we_write(1);
status = rtio_o_status_read(); status = rtio_o_status_read();
if(status) { 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) long long int rtio_get_counter(void)
{ {
rtio_counter_update_write(1); rtio_counter_update_write(1);
@ -81,16 +99,6 @@ long long int rtio_get(int channel, long long int time_limit)
return r; 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) void rtio_fud_sync(void)
{ {
while(rtio_get_counter() < previous_fud_end_time); while(rtio_get_counter() < previous_fud_end_time);
@ -102,14 +110,15 @@ void rtio_fud(long long int fud_time)
int status; int status;
rtio_chan_sel_write(RTIO_FUD_CHANNEL); rtio_chan_sel_write(RTIO_FUD_CHANNEL);
rtio_o_address_write(0);
fud_end_time = fud_time + 3*8; fud_end_time = fud_time + 3*8;
previous_fud_end_time = fud_end_time; previous_fud_end_time = fud_end_time;
rtio_o_timestamp_write(fud_time); rtio_o_timestamp_write(fud_time);
rtio_o_value_write(1); rtio_o_data_write(1);
rtio_o_we_write(1); rtio_o_we_write(1);
rtio_o_timestamp_write(fud_end_time); rtio_o_timestamp_write(fud_end_time);
rtio_o_value_write(0); rtio_o_data_write(0);
rtio_o_we_write(1); rtio_o_we_write(1);
status = rtio_o_status_read(); status = rtio_o_status_read();
if(status) { if(status) {

View File

@ -2,11 +2,11 @@
#define __RTIO_H #define __RTIO_H
void rtio_init(void); void rtio_init(void);
void rtio_oe(int channel, int oe); void rtio_set_o(long long int timestamp, int channel, int value);
void rtio_set(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_counter(void);
long long int rtio_get(int channel, long long int time_limit); 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_sync(void);
void rtio_fud(long long int fud_time); void rtio_fud(long long int fud_time);

View File

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

View File

@ -9,6 +9,7 @@ from misoclib.soc import mem_decoder
from targets.kc705 import MiniSoC from targets.kc705 import MiniSoC
from artiq.gateware import amp, rtio, ad9858, nist_qc1 from artiq.gateware import amp, rtio, ad9858, nist_qc1
from artiq.gateware.rtio.phy import ttl_simple
class _RTIOCRG(Module, AutoCSR): class _RTIOCRG(Module, AutoCSR):
@ -50,24 +51,36 @@ class _Peripherals(MiniSoC):
platform.request("user_led", 0), platform.request("user_led", 0),
platform.request("user_led", 1))) platform.request("user_led", 1)))
fud = Signal()
self.comb += [ self.comb += [
platform.request("ttl_l_tx_en").eq(1), platform.request("ttl_l_tx_en").eq(1),
platform.request("ttl_h_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.rtiocrg = _RTIOCRG(platform, self.crg.pll_sys)
self.submodules.rtiophy = rtio.phy.SimplePHY( self.submodules.rtio = rtio.RTIO(rtio_channels,
rtio_ins + rtio_outs, clk_freq=125000000)
output_only_pads=set(rtio_outs))
self.submodules.rtio = rtio.RTIO(self.rtiophy,
clk_freq=125000000,
ififo_depth=512)
dds_pads = platform.request("dds") dds_pads = platform.request("dds")
self.submodules.dds = ad9858.AD9858(dds_pads) self.submodules.dds = ad9858.AD9858(dds_pads)
@ -85,7 +98,7 @@ class UP(_Peripherals):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
_Peripherals.__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.submodules.rtiowb = wbgen.Bank(rtio_csrs)
self.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus) 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)
@ -93,6 +106,7 @@ class UP(_Peripherals):
self.add_wb_slave(mem_decoder(self.mem_map["dds"]), self.dds.bus) 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) self.add_memory_region("dds", self.mem_map["dds"] + 0x80000000, 64*4)
class AMP(_Peripherals): class AMP(_Peripherals):
csr_map = { csr_map = {
"kernel_cpu": 14 "kernel_cpu": 14
@ -112,7 +126,7 @@ class AMP(_Peripherals):
self.add_wb_slave(mem_decoder(self.mem_map["mailbox"]), self.mailbox.i1) 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) 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.submodules.rtiowb = wbgen.Bank(rtio_csrs)
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus) 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) 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.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) self.add_memory_region("dds", self.mem_map["dds"] + 0x80000000, 64*4)
default_subtarget = AMP default_subtarget = AMP

View File

@ -7,6 +7,7 @@ from misoclib.soc import mem_decoder
from targets.pipistrello import BaseSoC from targets.pipistrello import BaseSoC
from artiq.gateware import amp, rtio, ad9858, nist_qc1 from artiq.gateware import amp, rtio, ad9858, nist_qc1
from artiq.gateware.rtio.phy import ttl_simple
class _RTIOCRG(Module, AutoCSR): class _RTIOCRG(Module, AutoCSR):
@ -66,26 +67,46 @@ class _Peripherals(BaseSoC):
platform.request("user_led", 1), platform.request("user_led", 1),
)) ))
fud = Signal()
self.comb += [ self.comb += [
platform.request("ttl_l_tx_en").eq(1), platform.request("ttl_l_tx_en").eq(1),
platform.request("ttl_h_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.rtiocrg = _RTIOCRG(platform)
self.submodules.rtiophy = rtio.phy.SimplePHY( self.submodules.rtio = rtio.RTIO(rtio_channels,
rtio_ins + rtio_outs, clk_freq=125000000)
output_only_pads=set(rtio_outs))
self.submodules.rtio = rtio.RTIO(self.rtiophy,
clk_freq=125000000,
ififo_depth=512)
dds_pads = platform.request("dds") dds_pads = platform.request("dds")
self.submodules.dds = ad9858.AD9858(dds_pads) 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 targets.ppro import BaseSoC
from artiq.gateware import rtio, ad9858, nist_qc1 from artiq.gateware import rtio, ad9858, nist_qc1
from artiq.gateware.rtio.phy import ttl_simple
class _TestGen(Module): class _TestGen(Module):
@ -78,29 +79,39 @@ class UP(BaseSoC):
platform.request("user_led", 0), platform.request("user_led", 0),
platform.request("ext_led", 0))) platform.request("ext_led", 0)))
fud = Signal()
self.comb += [ self.comb += [
platform.request("ttl_l_tx_en").eq(1), platform.request("ttl_l_tx_en").eq(1),
platform.request("ttl_h_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.rtiocrg = _RTIOMiniCRG(platform)
self.submodules.rtiophy = rtio.phy.SimplePHY( self.submodules.rtio = rtio.RTIO(rtio_channels,
rtio_ins + rtio_outs,
output_only_pads=set(rtio_outs))
self.submodules.rtio = rtio.RTIO(self.rtiophy,
clk_freq=125000000, clk_freq=125000000,
counter_width=32, counter_width=32)
ififo_depth=512)
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.submodules.rtiowb = wbgen.Bank(rtio_csrs)
self.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus) 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: if with_test_gen:
self.submodules.test_gen = _TestGen(platform.request("ttl", 8)) self.submodules.test_gen = _TestGen(platform.request("ttl", 8))