mirror of https://github.com/m-labs/artiq.git
Merge branch 'master' into new-py2llvm
This commit is contained in:
commit
fd46d8b11e
|
@ -177,7 +177,7 @@ class TTLInOut:
|
||||||
self._set_sensitivity(0)
|
self._set_sensitivity(0)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_both_mu(self, duration):
|
def gate_both(self, duration):
|
||||||
"""Register both rising and falling edge events for the specified
|
"""Register both rising and falling edge events for the specified
|
||||||
duration (in seconds)."""
|
duration (in seconds)."""
|
||||||
self._set_sensitivity(3)
|
self._set_sensitivity(3)
|
||||||
|
@ -196,8 +196,8 @@ class TTLInOut:
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def timestamp_mu(self):
|
def timestamp_mu(self):
|
||||||
"""Poll the RTIO input and returns an event timestamp, according to
|
"""Poll the RTIO input and returns an event timestamp (in machine
|
||||||
the gating.
|
units), according to the gating.
|
||||||
|
|
||||||
If the gate is permanently closed, returns a negative value.
|
If the gate is permanently closed, returns a negative value.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -118,8 +118,10 @@ class _OutputManager(Module):
|
||||||
sequence_error = Signal()
|
sequence_error = Signal()
|
||||||
nop = Signal()
|
nop = Signal()
|
||||||
self.sync.rsys += [
|
self.sync.rsys += [
|
||||||
replace.eq(self.ev.timestamp == buf.timestamp[fine_ts_width:]),
|
replace.eq(self.ev.timestamp[fine_ts_width:] \
|
||||||
sequence_error.eq(self.ev.timestamp < buf.timestamp[fine_ts_width:])
|
== buf.timestamp[fine_ts_width:]),
|
||||||
|
sequence_error.eq(self.ev.timestamp[fine_ts_width:] \
|
||||||
|
< buf.timestamp[fine_ts_width:])
|
||||||
]
|
]
|
||||||
if interface.suppress_nop:
|
if interface.suppress_nop:
|
||||||
# disable NOP at reset: do not suppress a first write with all 0s
|
# disable NOP at reset: do not suppress a first write with all 0s
|
||||||
|
@ -300,8 +302,7 @@ class _KernelCSRs(AutoCSR):
|
||||||
|
|
||||||
|
|
||||||
class RTIO(Module):
|
class RTIO(Module):
|
||||||
def __init__(self, channels, clk_freq, full_ts_width=63,
|
def __init__(self, channels, full_ts_width=63, guard_io_cycles=20):
|
||||||
guard_io_cycles=20):
|
|
||||||
data_width = max(rtlink.get_data_width(c.interface)
|
data_width = max(rtlink.get_data_width(c.interface)
|
||||||
for c in channels)
|
for c in channels)
|
||||||
address_width = max(rtlink.get_address_width(c.interface)
|
address_width = max(rtlink.get_address_width(c.interface)
|
||||||
|
@ -329,11 +330,15 @@ class RTIO(Module):
|
||||||
self.cd_rsys.rst.eq(self.kcsrs.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.cd_rio,
|
self.specials += AsyncResetSynchronizer(
|
||||||
self.kcsrs.reset.storage)
|
self.cd_rio,
|
||||||
|
self.kcsrs.reset.storage | ResetSignal("rtio",
|
||||||
|
allow_reset_less=True))
|
||||||
self.comb += self.cd_rio_phy.clk.eq(ClockSignal("rtio"))
|
self.comb += self.cd_rio_phy.clk.eq(ClockSignal("rtio"))
|
||||||
self.specials += AsyncResetSynchronizer(self.cd_rio_phy,
|
self.specials += AsyncResetSynchronizer(
|
||||||
self.kcsrs.reset_phy.storage)
|
self.cd_rio_phy,
|
||||||
|
self.kcsrs.reset_phy.storage | ResetSignal("rtio",
|
||||||
|
allow_reset_less=True))
|
||||||
|
|
||||||
# Managers
|
# Managers
|
||||||
self.submodules.counter = _RTIOCounter(full_ts_width - fine_ts_width)
|
self.submodules.counter = _RTIOCounter(full_ts_width - fine_ts_width)
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
|
||||||
|
from artiq.gateware.rtio.phy import ttl_serdes_generic
|
||||||
|
|
||||||
|
|
||||||
|
class _OSERDESE2_8X(Module):
|
||||||
|
def __init__(self, pad):
|
||||||
|
self.o = Signal(8)
|
||||||
|
self.t_in = Signal()
|
||||||
|
self.t_out = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
o = self.o
|
||||||
|
self.specials += Instance("OSERDESE2",
|
||||||
|
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
|
||||||
|
p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1,
|
||||||
|
o_OQ=pad, o_TQ=self.t_out,
|
||||||
|
i_CLK=ClockSignal("rtiox4"),
|
||||||
|
i_CLKDIV=ClockSignal("rio_phy"),
|
||||||
|
i_D1=o[0], i_D2=o[1], i_D3=o[2], i_D4=o[3],
|
||||||
|
i_D5=o[4], i_D6=o[5], i_D7=o[6], i_D8=o[7],
|
||||||
|
i_TCE=1, i_OCE=1, i_RST=0,
|
||||||
|
i_T1=self.t_in)
|
||||||
|
|
||||||
|
|
||||||
|
class _IOSERDESE2_8X(Module):
|
||||||
|
def __init__(self, pad):
|
||||||
|
self.o = Signal(8)
|
||||||
|
self.i = Signal(8)
|
||||||
|
self.oe = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
pad_i = Signal()
|
||||||
|
pad_o = Signal()
|
||||||
|
i = self.i
|
||||||
|
self.specials += Instance("ISERDESE2", p_DATA_RATE="DDR",
|
||||||
|
p_DATA_WIDTH=8,
|
||||||
|
p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1,
|
||||||
|
o_Q1=i[7], o_Q2=i[6], o_Q3=i[5], o_Q4=i[4],
|
||||||
|
o_Q5=i[3], o_Q6=i[2], o_Q7=i[1], o_Q8=i[0],
|
||||||
|
i_D=pad_i,
|
||||||
|
i_CLK=ClockSignal("rtiox4"),
|
||||||
|
i_CLKB=~ClockSignal("rtiox4"),
|
||||||
|
i_CE1=1, i_RST=0,
|
||||||
|
i_CLKDIV=ClockSignal("rio_phy"))
|
||||||
|
oserdes = _OSERDESE2_8X(pad_o)
|
||||||
|
self.submodules += oserdes
|
||||||
|
self.specials += Instance("IOBUF",
|
||||||
|
i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out,
|
||||||
|
io_IO=pad)
|
||||||
|
self.comb += [
|
||||||
|
oserdes.t_in.eq(~self.oe),
|
||||||
|
oserdes.o.eq(self.o)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Output_8X(ttl_serdes_generic.Output):
|
||||||
|
def __init__(self, pad):
|
||||||
|
serdes = _OSERDESE2_8X(pad)
|
||||||
|
self.submodules += serdes
|
||||||
|
ttl_serdes_generic.Output.__init__(self, serdes)
|
||||||
|
|
||||||
|
|
||||||
|
class Inout_8X(ttl_serdes_generic.Inout):
|
||||||
|
def __init__(self, pad):
|
||||||
|
serdes = _IOSERDESE2_8X(pad)
|
||||||
|
self.submodules += serdes
|
||||||
|
ttl_serdes_generic.Inout.__init__(self, serdes)
|
|
@ -0,0 +1,273 @@
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
from migen.genlib.coding import PriorityEncoder
|
||||||
|
|
||||||
|
from artiq.gateware.rtio import rtlink
|
||||||
|
|
||||||
|
|
||||||
|
def _mk_edges(w, direction):
|
||||||
|
l = [(1 << i) - 1 for i in range(w)]
|
||||||
|
if direction == "rising":
|
||||||
|
l = [2**w - 1 ^ x for x in l]
|
||||||
|
elif direction == "falling":
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
return l
|
||||||
|
|
||||||
|
|
||||||
|
class _SerdesDriver(Module):
|
||||||
|
def __init__(self, serdes_o, stb, data, fine_ts, override_en, override_o):
|
||||||
|
previous_data = Signal()
|
||||||
|
serdes_width = flen(serdes_o)
|
||||||
|
edges = Array(_mk_edges(serdes_width, "rising"))
|
||||||
|
edges_n = Array(_mk_edges(serdes_width, "falling"))
|
||||||
|
self.sync.rio_phy += [
|
||||||
|
If(stb, previous_data.eq(data)),
|
||||||
|
If(override_en,
|
||||||
|
serdes_o.eq(Replicate(override_o, serdes_width))
|
||||||
|
).Else(
|
||||||
|
If(stb & ~previous_data & data,
|
||||||
|
serdes_o.eq(edges[fine_ts]),
|
||||||
|
).Elif(stb & previous_data & ~data,
|
||||||
|
serdes_o.eq(edges_n[fine_ts]),
|
||||||
|
).Else(
|
||||||
|
serdes_o.eq(Replicate(previous_data, serdes_width)),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Output(Module):
|
||||||
|
def __init__(self, serdes):
|
||||||
|
self.rtlink = rtlink.Interface(
|
||||||
|
rtlink.OInterface(1, fine_ts_width=log2_int(flen(serdes.o))))
|
||||||
|
self.probes = [serdes.o[-1]]
|
||||||
|
override_en = Signal()
|
||||||
|
override_o = Signal()
|
||||||
|
self.overrides = [override_en, override_o]
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
self.submodules += _SerdesDriver(
|
||||||
|
serdes.o,
|
||||||
|
self.rtlink.o.stb, self.rtlink.o.data, self.rtlink.o.fine_ts,
|
||||||
|
override_en, override_o)
|
||||||
|
|
||||||
|
|
||||||
|
class Inout(Module):
|
||||||
|
def __init__(self, serdes):
|
||||||
|
serdes_width = flen(serdes.o)
|
||||||
|
assert flen(serdes.i) == serdes_width
|
||||||
|
self.rtlink = rtlink.Interface(
|
||||||
|
rtlink.OInterface(2, 2, fine_ts_width=log2_int(serdes_width)),
|
||||||
|
rtlink.IInterface(1, fine_ts_width=log2_int(serdes_width)))
|
||||||
|
self.probes = [serdes.i[-1], serdes.oe]
|
||||||
|
override_en = Signal()
|
||||||
|
override_o = Signal()
|
||||||
|
override_oe = Signal()
|
||||||
|
self.overrides = [override_en, override_o, override_oe]
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
# Output
|
||||||
|
self.submodules += _SerdesDriver(
|
||||||
|
serdes_o=serdes.o,
|
||||||
|
stb=self.rtlink.o.stb & (self.rtlink.o.address == 0),
|
||||||
|
data=self.rtlink.o.data[0],
|
||||||
|
fine_ts=self.rtlink.o.fine_ts,
|
||||||
|
override_en=override_en, override_o=override_o)
|
||||||
|
|
||||||
|
oe_k = Signal()
|
||||||
|
self.sync.rio_phy += [
|
||||||
|
If(self.rtlink.o.stb & (self.rtlink.o.address == 1),
|
||||||
|
oe_k.eq(self.rtlink.o.data[0])),
|
||||||
|
If(override_en,
|
||||||
|
serdes.oe.eq(override_oe)
|
||||||
|
).Else(
|
||||||
|
serdes.oe.eq(oe_k)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Input
|
||||||
|
sensitivity = Signal(2)
|
||||||
|
self.sync.rio += If(self.rtlink.o.stb & (self.rtlink.o.address == 2),
|
||||||
|
sensitivity.eq(self.rtlink.o.data))
|
||||||
|
|
||||||
|
i = serdes.i[-1]
|
||||||
|
i_d = Signal()
|
||||||
|
self.sync.rio_phy += [
|
||||||
|
i_d.eq(i),
|
||||||
|
self.rtlink.i.stb.eq(
|
||||||
|
(sensitivity[0] & ( i & ~i_d)) |
|
||||||
|
(sensitivity[1] & (~i & i_d))
|
||||||
|
),
|
||||||
|
self.rtlink.i.data.eq(i),
|
||||||
|
]
|
||||||
|
|
||||||
|
pe = PriorityEncoder(serdes_width)
|
||||||
|
self.submodules += pe
|
||||||
|
self.comb += pe.i.eq(serdes.i ^ Replicate(i_d, serdes_width))
|
||||||
|
self.sync.rio_phy += self.rtlink.i.fine_ts.eq(pe.o)
|
||||||
|
|
||||||
|
|
||||||
|
class _FakeSerdes(Module):
|
||||||
|
def __init__(self):
|
||||||
|
self.o = Signal(8)
|
||||||
|
self.i = Signal(8)
|
||||||
|
self.oe = Signal()
|
||||||
|
|
||||||
|
|
||||||
|
class _OutputTB(Module):
|
||||||
|
def __init__(self):
|
||||||
|
serdes = _FakeSerdes()
|
||||||
|
self.submodules.dut = RenameClockDomains(Output(serdes),
|
||||||
|
{"rio_phy": "sys"})
|
||||||
|
|
||||||
|
def gen_simulation(self, selfp):
|
||||||
|
selfp.dut.rtlink.o.data = 1
|
||||||
|
selfp.dut.rtlink.o.fine_ts = 1
|
||||||
|
selfp.dut.rtlink.o.stb = 1
|
||||||
|
yield
|
||||||
|
selfp.dut.rtlink.o.stb = 0
|
||||||
|
yield
|
||||||
|
selfp.dut.rtlink.o.data = 0
|
||||||
|
selfp.dut.rtlink.o.fine_ts = 2
|
||||||
|
selfp.dut.rtlink.o.stb = 1
|
||||||
|
yield
|
||||||
|
yield
|
||||||
|
selfp.dut.rtlink.o.data = 1
|
||||||
|
selfp.dut.rtlink.o.fine_ts = 7
|
||||||
|
selfp.dut.rtlink.o.stb = 1
|
||||||
|
for _ in range(6):
|
||||||
|
# note that stb stays active; output should not change
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
class _InoutTB(Module):
|
||||||
|
def __init__(self):
|
||||||
|
self.serdes = _FakeSerdes()
|
||||||
|
self.submodules.dut = RenameClockDomains(Inout(self.serdes),
|
||||||
|
{"rio_phy": "sys",
|
||||||
|
"rio": "sys"})
|
||||||
|
|
||||||
|
def check_input(self, selfp, stb, fine_ts=None):
|
||||||
|
if stb != selfp.dut.rtlink.i.stb:
|
||||||
|
print("KO rtlink.i.stb should be {} but is {}"
|
||||||
|
.format(stb, selfp.dut.rtlink.i.stb))
|
||||||
|
elif fine_ts is not None and fine_ts != selfp.dut.rtlink.i.fine_ts:
|
||||||
|
print("KO rtlink.i.fine_ts should be {} but is {}"
|
||||||
|
.format(fine_ts, selfp.dut.rtlink.i.fine_ts))
|
||||||
|
else:
|
||||||
|
print("OK")
|
||||||
|
|
||||||
|
def check_output(self, selfp, data):
|
||||||
|
if selfp.serdes.o != data:
|
||||||
|
print("KO io.o should be {} but is {}".format(data, selfp.serdes.o))
|
||||||
|
else:
|
||||||
|
print("OK")
|
||||||
|
|
||||||
|
def check_output_enable(self, selfp, oe):
|
||||||
|
if selfp.serdes.oe != oe:
|
||||||
|
print("KO io.oe should be {} but is {}".format(oe, selfp.serdes.oe))
|
||||||
|
else:
|
||||||
|
print("OK")
|
||||||
|
|
||||||
|
def gen_simulation(self, selfp):
|
||||||
|
selfp.dut.rtlink.o.address = 2
|
||||||
|
selfp.dut.rtlink.o.data = 0b11
|
||||||
|
selfp.dut.rtlink.o.stb = 1 # set sensitivity to rising + falling
|
||||||
|
yield
|
||||||
|
selfp.dut.rtlink.o.stb = 0
|
||||||
|
|
||||||
|
self.check_output_enable(selfp, 0)
|
||||||
|
yield
|
||||||
|
|
||||||
|
selfp.serdes.i = 0b11111110 # rising edge at fine_ts = 1
|
||||||
|
yield
|
||||||
|
selfp.serdes.i = 0b11111111
|
||||||
|
yield
|
||||||
|
self.check_input(selfp, stb=1, fine_ts=1)
|
||||||
|
|
||||||
|
selfp.serdes.i = 0b01111111 # falling edge at fine_ts = 7
|
||||||
|
yield
|
||||||
|
selfp.serdes.i = 0b00000000
|
||||||
|
yield
|
||||||
|
self.check_input(selfp, stb=1, fine_ts=7)
|
||||||
|
|
||||||
|
selfp.serdes.i = 0b11000000 # rising edge at fine_ts = 6
|
||||||
|
yield
|
||||||
|
selfp.serdes.i = 0b11111111
|
||||||
|
yield
|
||||||
|
self.check_input(selfp, stb=1, fine_ts=6)
|
||||||
|
|
||||||
|
selfp.dut.rtlink.o.address = 2
|
||||||
|
selfp.dut.rtlink.o.data = 0b11
|
||||||
|
selfp.dut.rtlink.o.stb = 1 # set sensitivity to rising only
|
||||||
|
yield
|
||||||
|
selfp.dut.rtlink.o.stb = 0
|
||||||
|
yield
|
||||||
|
|
||||||
|
selfp.serdes.i = 0b00001111 # falling edge at fine_ts = 4
|
||||||
|
yield
|
||||||
|
self.check_input(selfp, stb=0) # no strobe, sensitivity is rising edge
|
||||||
|
|
||||||
|
selfp.serdes.i = 0b11110000 # rising edge at fine_ts = 4
|
||||||
|
yield
|
||||||
|
self.check_input(selfp, stb=1, fine_ts=4)
|
||||||
|
|
||||||
|
selfp.dut.rtlink.o.address = 1
|
||||||
|
selfp.dut.rtlink.o.data = 1
|
||||||
|
selfp.dut.rtlink.o.stb = 1 # set Output Enable to 1
|
||||||
|
yield
|
||||||
|
selfp.dut.rtlink.o.stb = 0
|
||||||
|
yield
|
||||||
|
yield
|
||||||
|
self.check_output_enable(selfp, 1)
|
||||||
|
|
||||||
|
selfp.dut.rtlink.o.address = 0
|
||||||
|
selfp.dut.rtlink.o.data = 1
|
||||||
|
selfp.dut.rtlink.o.fine_ts = 3
|
||||||
|
selfp.dut.rtlink.o.stb = 1 # rising edge at fine_ts = 3
|
||||||
|
yield
|
||||||
|
selfp.dut.rtlink.o.stb = 0
|
||||||
|
yield
|
||||||
|
self.check_output(selfp, data=0b11111000)
|
||||||
|
|
||||||
|
yield
|
||||||
|
self.check_output(selfp, data=0xFF) # stays at 1
|
||||||
|
|
||||||
|
selfp.dut.rtlink.o.data = 0
|
||||||
|
selfp.dut.rtlink.o.fine_ts = 0
|
||||||
|
selfp.dut.rtlink.o.stb = 1 # falling edge at fine_ts = 0
|
||||||
|
yield
|
||||||
|
selfp.dut.rtlink.o.stb = 0
|
||||||
|
yield
|
||||||
|
self.check_output(selfp, data=0)
|
||||||
|
|
||||||
|
yield
|
||||||
|
self.check_output(selfp, data=0)
|
||||||
|
|
||||||
|
selfp.dut.rtlink.o.data = 1
|
||||||
|
selfp.dut.rtlink.o.fine_ts = 7
|
||||||
|
selfp.dut.rtlink.o.stb = 1 # rising edge at fine_ts = 7
|
||||||
|
yield
|
||||||
|
selfp.dut.rtlink.o.stb = 0
|
||||||
|
yield
|
||||||
|
self.check_output(selfp, data=0b10000000)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
from migen.sim.generic import Simulator, TopLevel
|
||||||
|
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print("Incorrect command line")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
cls = {
|
||||||
|
"output": _OutputTB,
|
||||||
|
"inout": _InoutTB
|
||||||
|
}[sys.argv[1]]
|
||||||
|
|
||||||
|
with Simulator(cls(), TopLevel("top.vcd", clk_period=int(1/0.125))) as s:
|
||||||
|
s.run()
|
|
@ -0,0 +1,154 @@
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
|
||||||
|
from artiq.gateware.rtio.phy import ttl_serdes_generic
|
||||||
|
|
||||||
|
|
||||||
|
class _OSERDES2_8X(Module):
|
||||||
|
def __init__(self, pad, stb):
|
||||||
|
self.o = Signal(8)
|
||||||
|
self.t_in = Signal()
|
||||||
|
self.t_out = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
cascade = Signal(4)
|
||||||
|
o = self.o
|
||||||
|
common = dict(p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
|
||||||
|
p_DATA_WIDTH=8, p_OUTPUT_MODE="SINGLE_ENDED", i_TRAIN=0,
|
||||||
|
i_CLK0=ClockSignal("rtiox8"), i_CLK1=0,
|
||||||
|
i_CLKDIV=ClockSignal("rio_phy"),
|
||||||
|
i_IOCE=stb, i_OCE=1, i_TCE=1, i_RST=0,
|
||||||
|
i_T4=self.t_in, i_T3=self.t_in,
|
||||||
|
i_T2=self.t_in, i_T1=self.t_in)
|
||||||
|
|
||||||
|
self.specials += [
|
||||||
|
Instance("OSERDES2", p_SERDES_MODE="MASTER",
|
||||||
|
i_D4=o[7], i_D3=o[6], i_D2=o[5], i_D1=o[4],
|
||||||
|
i_SHIFTIN1=1, i_SHIFTIN2=1,
|
||||||
|
i_SHIFTIN3=cascade[2], i_SHIFTIN4=cascade[3],
|
||||||
|
o_SHIFTOUT1=cascade[0], o_SHIFTOUT2=cascade[1],
|
||||||
|
o_OQ=pad, o_TQ=self.t_out, **common),
|
||||||
|
Instance("OSERDES2", p_SERDES_MODE="SLAVE",
|
||||||
|
i_D4=o[3], i_D3=o[2], i_D2=o[1], i_D1=o[0],
|
||||||
|
i_SHIFTIN1=cascade[0], i_SHIFTIN2=cascade[1],
|
||||||
|
i_SHIFTIN3=1, i_SHIFTIN4=1,
|
||||||
|
o_SHIFTOUT3=cascade[2], o_SHIFTOUT4=cascade[3],
|
||||||
|
**common),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class _IOSERDES2_8X(Module):
|
||||||
|
def __init__(self, pad, stb):
|
||||||
|
self.o = Signal(8)
|
||||||
|
self.i = Signal(8)
|
||||||
|
self.oe = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
pad_i = Signal()
|
||||||
|
pad_o = Signal()
|
||||||
|
cascade = Signal()
|
||||||
|
i = self.i
|
||||||
|
common = dict(p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR",
|
||||||
|
p_DATA_WIDTH=8, p_INTERFACE_TYPE="RETIMED",
|
||||||
|
i_BITSLIP=0, i_CE0=1, i_IOCE=stb,
|
||||||
|
i_RST=0, i_CLK0=ClockSignal("rtiox8"), i_CLK1=0,
|
||||||
|
i_CLKDIV=ClockSignal("rio_phy"))
|
||||||
|
self.specials += [
|
||||||
|
Instance("ISERDES2", p_SERDES_MODE="MASTER",
|
||||||
|
o_Q4=i[7], o_Q3=i[6], o_Q2=i[5], o_Q1=i[4],
|
||||||
|
o_SHIFTOUT=cascade, i_D=pad_i, i_SHIFTIN=0,
|
||||||
|
**common),
|
||||||
|
Instance("ISERDES2", p_SERDES_MODE="SLAVE",
|
||||||
|
o_Q4=i[3], o_Q3=i[2], o_Q2=i[1], o_Q1=i[0],
|
||||||
|
i_D=0, i_SHIFTIN=cascade, **common),
|
||||||
|
]
|
||||||
|
|
||||||
|
oserdes = _OSERDES2_8X(pad_o, stb)
|
||||||
|
self.submodules += oserdes
|
||||||
|
self.specials += Instance("IOBUF",
|
||||||
|
i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out,
|
||||||
|
io_IO=pad)
|
||||||
|
self.comb += [
|
||||||
|
oserdes.t_in.eq(~self.oe),
|
||||||
|
oserdes.o.eq(self.o),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Output_8X(ttl_serdes_generic.Output):
|
||||||
|
def __init__(self, pad, stb):
|
||||||
|
serdes = _OSERDES2_8X(pad, stb)
|
||||||
|
self.submodules += serdes
|
||||||
|
ttl_serdes_generic.Output.__init__(self, serdes)
|
||||||
|
|
||||||
|
|
||||||
|
class Inout_8X(ttl_serdes_generic.Inout):
|
||||||
|
def __init__(self, pad, stb):
|
||||||
|
serdes = _IOSERDES2_8X(pad, stb)
|
||||||
|
self.submodules += serdes
|
||||||
|
ttl_serdes_generic.Inout.__init__(self, serdes)
|
||||||
|
|
||||||
|
|
||||||
|
class _OSERDES2_4X(Module):
|
||||||
|
def __init__(self, pad, stb):
|
||||||
|
self.o = Signal(4)
|
||||||
|
self.t_in = Signal()
|
||||||
|
self.t_out = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
o = self.o
|
||||||
|
self.specials += Instance("OSERDES2", p_SERDES_MODE="NONE",
|
||||||
|
p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
|
||||||
|
p_DATA_WIDTH=4, p_OUTPUT_MODE="SINGLE_ENDED",
|
||||||
|
i_TRAIN=0, i_CLK0=ClockSignal("rtiox4"),
|
||||||
|
i_CLK1=0, i_CLKDIV=ClockSignal("rio_phy"),
|
||||||
|
i_IOCE=stb, i_OCE=1, i_TCE=1, i_RST=0,
|
||||||
|
i_T4=self.t_in, i_T3=self.t_in,
|
||||||
|
i_T2=self.t_in, i_T1=self.t_in,
|
||||||
|
i_D4=o[3], i_D3=o[2], i_D2=o[1], i_D1=o[0],
|
||||||
|
o_OQ=pad, o_TQ=self.t_out)
|
||||||
|
|
||||||
|
|
||||||
|
class _IOSERDES2_4X(Module):
|
||||||
|
def __init__(self, pad, stb):
|
||||||
|
self.o = Signal(4)
|
||||||
|
self.i = Signal(4)
|
||||||
|
self.oe = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
pad_i = Signal()
|
||||||
|
pad_o = Signal()
|
||||||
|
i = self.i
|
||||||
|
self.specials += Instance("ISERDES2", p_SERDES_MODE="NONE",
|
||||||
|
p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR",
|
||||||
|
p_DATA_WIDTH=4, p_INTERFACE_TYPE="RETIMED",
|
||||||
|
i_BITSLIP=0, i_CE0=1, i_IOCE=stb,
|
||||||
|
i_RST=0, i_CLK0=ClockSignal("rtiox4"),
|
||||||
|
i_CLK1=0, i_CLKDIV=ClockSignal("rio_phy"),
|
||||||
|
o_Q4=i[3], o_Q3=i[2], o_Q2=i[1], o_Q1=i[0],
|
||||||
|
i_D=pad_i, i_SHIFTIN=0)
|
||||||
|
oserdes = _OSERDES2_4X(pad_o, stb)
|
||||||
|
self.submodules += oserdes
|
||||||
|
self.specials += Instance("IOBUF",
|
||||||
|
i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out,
|
||||||
|
io_IO=pad)
|
||||||
|
self.comb += [
|
||||||
|
oserdes.t_in.eq(~self.oe),
|
||||||
|
oserdes.o.eq(self.o),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Output_4X(ttl_serdes_generic.Output):
|
||||||
|
def __init__(self, pad, stb):
|
||||||
|
serdes = _OSERDES2_4X(pad, stb)
|
||||||
|
self.submodules += serdes
|
||||||
|
ttl_serdes_generic.Output.__init__(self, serdes)
|
||||||
|
|
||||||
|
|
||||||
|
class Inout_4X(ttl_serdes_generic.Inout):
|
||||||
|
def __init__(self, pad, stb):
|
||||||
|
serdes = _IOSERDES2_4X(pad, stb)
|
||||||
|
self.submodules += serdes
|
||||||
|
ttl_serdes_generic.Inout.__init__(self, serdes)
|
|
@ -120,7 +120,7 @@ class LoopbackCount(EnvExperiment):
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
self.ttl_inout.output()
|
self.ttl_inout.output()
|
||||||
delay(1*us)
|
delay(5*us)
|
||||||
with parallel:
|
with parallel:
|
||||||
self.ttl_inout.gate_rising(10*us)
|
self.ttl_inout.gate_rising(10*us)
|
||||||
with sequential:
|
with sequential:
|
||||||
|
|
|
@ -147,7 +147,7 @@ These steps are required to generate bitstream (``.bit``) files, build the MiSoC
|
||||||
::
|
::
|
||||||
|
|
||||||
$ cd ~/artiq-dev
|
$ cd ~/artiq-dev
|
||||||
$ svn co https://xc3sprog.svn.sourceforge.net/svnroot/xc3sprog/trunk xc3sprog
|
$ svn co http://svn.code.sf.net/p/xc3sprog/code/trunk xc3sprog
|
||||||
$ cd xc3sprog
|
$ cd xc3sprog
|
||||||
$ cmake . && make
|
$ cmake . && make
|
||||||
$ sudo make install
|
$ sudo make install
|
||||||
|
@ -299,16 +299,14 @@ Installing the host-side software
|
||||||
* Install the llvmlite Python bindings: ::
|
* Install the llvmlite Python bindings: ::
|
||||||
|
|
||||||
$ cd ~/artiq-dev
|
$ cd ~/artiq-dev
|
||||||
$ git clone https://github.com/numba/llvmlite
|
$ git clone https://github.com/m-labs/llvmlite
|
||||||
|
$ git checkout backport-3.5
|
||||||
$ cd llvmlite
|
$ cd llvmlite
|
||||||
$ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-add-all-targets.patch
|
$ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-add-all-targets.patch
|
||||||
$ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-rename.patch
|
$ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-rename.patch
|
||||||
$ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-build-as-debug-on-windows.patch
|
$ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-build-as-debug-on-windows.patch
|
||||||
$ LLVM_CONFIG=/usr/local/llvm-or1k/bin/llvm-config python3 setup.py install --user
|
$ LLVM_CONFIG=/usr/local/llvm-or1k/bin/llvm-config python3 setup.py install --user
|
||||||
|
|
||||||
.. note::
|
|
||||||
llvmlite is in development and its API is not stable yet. Commit ID ``11a8303d02e3d6dd2d1e0e9065701795cd8a979f`` is known to work.
|
|
||||||
|
|
||||||
* Install ARTIQ: ::
|
* Install ARTIQ: ::
|
||||||
|
|
||||||
$ cd ~/artiq-dev
|
$ cd ~/artiq-dev
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"module": "artiq.coredevice.core",
|
"module": "artiq.coredevice.core",
|
||||||
"class": "Core",
|
"class": "Core",
|
||||||
"arguments": {}
|
"arguments": {"ref_period": 1e-9}
|
||||||
},
|
},
|
||||||
|
|
||||||
"pmt0": {
|
"pmt0": {
|
||||||
|
@ -133,6 +133,9 @@
|
||||||
"command": "lda_controller -p {port} --bind {bind}"
|
"command": "lda_controller -p {port} --bind {bind}"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"ttl_inout": "pmt0",
|
||||||
|
"ttl_out": "ttl0",
|
||||||
|
|
||||||
"pmt": "pmt0",
|
"pmt": "pmt0",
|
||||||
"bd_dds": "dds0",
|
"bd_dds": "dds0",
|
||||||
"bd_sw": "ttl0",
|
"bd_sw": "ttl0",
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
from artiq import *
|
||||||
|
|
||||||
|
|
||||||
|
class PulseNotReceivedError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TDR(EnvExperiment):
|
||||||
|
"""Time domain reflectometer.
|
||||||
|
|
||||||
|
From ttl2 an impedance matched pulse is send onto a coax
|
||||||
|
cable with an open end. pmt0 (very short stub, high impedance) also
|
||||||
|
listens on the transmission line near ttl2.
|
||||||
|
|
||||||
|
When the forward propagating pulse passes pmt0, the voltage is half of the
|
||||||
|
logic voltage and does not register as a rising edge. Once the
|
||||||
|
rising edge is reflected at an open end (same sign) and passes by pmt0 on
|
||||||
|
its way back to ttl2, it is detected. Analogously, hysteresis leads to
|
||||||
|
detection of the falling edge once the reflection reaches pmt0 after
|
||||||
|
one round trip time.
|
||||||
|
|
||||||
|
This works marginally and is just a proof of principle: it relies on
|
||||||
|
hysteresis at FPGA inputs around half voltage and good impedance steps,
|
||||||
|
as well as reasonably low loss cable. It does not work well for longer
|
||||||
|
cables (>100 ns RTT). The default drive strength of 12 mA and 3.3 V would
|
||||||
|
be ~300 Ω but it seems 40 Ω series impedance at the output matches
|
||||||
|
the hysteresis of the input.
|
||||||
|
|
||||||
|
This is also equivalent to a loopback tester or a delay measurement.
|
||||||
|
"""
|
||||||
|
def build(self):
|
||||||
|
self.attr_device("core")
|
||||||
|
self.attr_device("pmt0")
|
||||||
|
self.attr_device("ttl2")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
n = 1000 # repetitions
|
||||||
|
latency = 50e-9 # calibrated latency without a transmission line
|
||||||
|
pulse = 1e-6 # pulse length, larger than rtt
|
||||||
|
try:
|
||||||
|
self.many(n, seconds_to_mu(pulse, self.core))
|
||||||
|
except PulseNotReceivedError:
|
||||||
|
print("to few edges: cable too long or wiring bad")
|
||||||
|
else:
|
||||||
|
print(self.t)
|
||||||
|
t_rise = mu_to_seconds(self.t[0], self.core)/n - latency
|
||||||
|
t_fall = mu_to_seconds(self.t[1], self.core)/n - latency - pulse
|
||||||
|
print("round trip times:")
|
||||||
|
print("rising: {:5g} ns, falling {:5g} ns".format(
|
||||||
|
t_rise/1e-9, t_fall/1e-9))
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def many(self, n, p):
|
||||||
|
t = [0 for i in range(2)]
|
||||||
|
self.core.break_realtime()
|
||||||
|
for i in range(n):
|
||||||
|
self.one(t, p)
|
||||||
|
self.t = t
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def one(self, t, p):
|
||||||
|
t0 = now_mu()
|
||||||
|
with parallel:
|
||||||
|
self.pmt0.gate_both_mu(2*p)
|
||||||
|
self.ttl2.pulse_mu(p)
|
||||||
|
for i in range(len(t)):
|
||||||
|
ti = self.pmt0.timestamp_mu()
|
||||||
|
if ti <= 0:
|
||||||
|
raise PulseNotReceivedError
|
||||||
|
t[i] += ti - t0
|
||||||
|
self.pmt0.count() # flush
|
|
@ -1,6 +1,6 @@
|
||||||
include $(MSCDIR)/software/common.mak
|
include $(MSCDIR)/software/common.mak
|
||||||
|
|
||||||
OBJECTS := isr.o flash_storage.o clock.o elf_loader.o services.o session.o log.o test_mode.o kloader.o bridge_ctl.o mailbox.o ksupport_data.o kserver.o moninj.o main.o
|
OBJECTS := isr.o flash_storage.o clock.o rtiocrg.o elf_loader.o services.o session.o log.o test_mode.o kloader.o bridge_ctl.o mailbox.o ksupport_data.o kserver.o moninj.o main.o
|
||||||
OBJECTS_KSUPPORT := ksupport.o exception_jmp.o exceptions.o mailbox.o bridge.o rtio.o ttl.o dds.o
|
OBJECTS_KSUPPORT := ksupport.o exception_jmp.o exceptions.o mailbox.o bridge.o rtio.o ttl.o dds.o
|
||||||
|
|
||||||
CFLAGS += -Ilwip/src/include -Iliblwip
|
CFLAGS += -Ilwip/src/include -Iliblwip
|
||||||
|
|
|
@ -5,12 +5,14 @@
|
||||||
#include "dds.h"
|
#include "dds.h"
|
||||||
#include "bridge.h"
|
#include "bridge.h"
|
||||||
|
|
||||||
|
#define TIME_BUFFER (8000 << RTIO_FINE_TS_WIDTH)
|
||||||
|
|
||||||
static void dds_write(int addr, int data)
|
static void dds_write(int addr, int data)
|
||||||
{
|
{
|
||||||
rtio_chan_sel_write(RTIO_DDS_CHANNEL);
|
rtio_chan_sel_write(RTIO_DDS_CHANNEL);
|
||||||
rtio_o_address_write(addr);
|
rtio_o_address_write(addr);
|
||||||
rtio_o_data_write(data);
|
rtio_o_data_write(data);
|
||||||
rtio_o_timestamp_write(rtio_get_counter() + 8000);
|
rtio_o_timestamp_write(rtio_get_counter() + TIME_BUFFER);
|
||||||
rtio_o_we_write(1);
|
rtio_o_we_write(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +48,7 @@ void bridge_main(void)
|
||||||
struct msg_brg_ttl_out *msg;
|
struct msg_brg_ttl_out *msg;
|
||||||
|
|
||||||
msg = (struct msg_brg_ttl_out *)umsg;
|
msg = (struct msg_brg_ttl_out *)umsg;
|
||||||
ttl_set_oe(rtio_get_counter() + 8000, msg->channel, msg->value);
|
ttl_set_oe(rtio_get_counter() + TIME_BUFFER, msg->channel, msg->value);
|
||||||
mailbox_acknowledge();
|
mailbox_acknowledge();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +56,7 @@ void bridge_main(void)
|
||||||
struct msg_brg_ttl_out *msg;
|
struct msg_brg_ttl_out *msg;
|
||||||
|
|
||||||
msg = (struct msg_brg_ttl_out *)umsg;
|
msg = (struct msg_brg_ttl_out *)umsg;
|
||||||
ttl_set_o(rtio_get_counter() + 8000, msg->channel, msg->value);
|
ttl_set_o(rtio_get_counter() + TIME_BUFFER, msg->channel, msg->value);
|
||||||
mailbox_acknowledge();
|
mailbox_acknowledge();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,16 @@ long long int clock_get_ms(void)
|
||||||
return clock_ms;
|
return clock_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void busywait_us(long long int us)
|
||||||
|
{
|
||||||
|
long long int threshold;
|
||||||
|
|
||||||
|
timer0_update_value_write(1);
|
||||||
|
threshold = timer0_value_read() - us*(long long int)identifier_frequency_read()/1000000LL;
|
||||||
|
while(timer0_value_read() > threshold)
|
||||||
|
timer0_update_value_write(1);
|
||||||
|
}
|
||||||
|
|
||||||
struct watchdog {
|
struct watchdog {
|
||||||
int active;
|
int active;
|
||||||
long long int threshold;
|
long long int threshold;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
void clock_init(void);
|
void clock_init(void);
|
||||||
long long int clock_get_ms(void);
|
long long int clock_get_ms(void);
|
||||||
|
void busywait_us(long long us);
|
||||||
|
|
||||||
#define MAX_WATCHDOGS 16
|
#define MAX_WATCHDOGS 16
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define __KLOADER_H
|
#define __KLOADER_H
|
||||||
|
|
||||||
#define KERNELCPU_EXEC_ADDRESS 0x40400000
|
#define KERNELCPU_EXEC_ADDRESS 0x40400000
|
||||||
#define KERNELCPU_PAYLOAD_ADDRESS 0x40404000
|
#define KERNELCPU_PAYLOAD_ADDRESS 0x40408000
|
||||||
|
|
||||||
extern long long int now;
|
extern long long int now;
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ long long int now_init(void)
|
||||||
|
|
||||||
if(now < 0) {
|
if(now < 0) {
|
||||||
rtio_init();
|
rtio_init();
|
||||||
now = rtio_get_counter() + 125000;
|
now = rtio_get_counter() + (125000 << RTIO_FINE_TS_WIDTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
return now;
|
return now;
|
||||||
|
|
|
@ -4,10 +4,10 @@ ENTRY(_start)
|
||||||
INCLUDE generated/regions.ld
|
INCLUDE generated/regions.ld
|
||||||
|
|
||||||
/* First 4M of main memory are reserved for runtime code/data
|
/* First 4M of main memory are reserved for runtime code/data
|
||||||
* then comes kernel memory. First 16K of kernel memory are for support code.
|
* then comes kernel memory. First 32K of kernel memory are for support code.
|
||||||
*/
|
*/
|
||||||
MEMORY {
|
MEMORY {
|
||||||
ksupport : ORIGIN = 0x40400000, LENGTH = 0x4000
|
ksupport : ORIGIN = 0x40400000, LENGTH = 0x8000
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On AMP systems, kernel stack is at the end of main RAM,
|
/* On AMP systems, kernel stack is at the end of main RAM,
|
||||||
|
@ -24,17 +24,6 @@ SECTIONS
|
||||||
_etext = .;
|
_etext = .;
|
||||||
} > ksupport
|
} > ksupport
|
||||||
|
|
||||||
.got :
|
|
||||||
{
|
|
||||||
_GLOBAL_OFFSET_TABLE_ = .;
|
|
||||||
*(.got)
|
|
||||||
} > ksupport
|
|
||||||
|
|
||||||
.got.plt :
|
|
||||||
{
|
|
||||||
*(.got.plt)
|
|
||||||
} > ksupport
|
|
||||||
|
|
||||||
.rodata :
|
.rodata :
|
||||||
{
|
{
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
|
|
@ -53,4 +53,3 @@ clean:
|
||||||
|
|
||||||
liblwip.a: $(LWIPOBJS)
|
liblwip.a: $(LWIPOBJS)
|
||||||
$(AR) clr liblwip.a $(LWIPOBJS)
|
$(AR) clr liblwip.a $(LWIPOBJS)
|
||||||
$(RANLIB) liblwip.a
|
|
||||||
|
|
|
@ -26,17 +26,6 @@ SECTIONS
|
||||||
_etext = .;
|
_etext = .;
|
||||||
} > runtime
|
} > runtime
|
||||||
|
|
||||||
.got :
|
|
||||||
{
|
|
||||||
_GLOBAL_OFFSET_TABLE_ = .;
|
|
||||||
*(.got)
|
|
||||||
} > runtime
|
|
||||||
|
|
||||||
.got.plt :
|
|
||||||
{
|
|
||||||
*(.got.plt)
|
|
||||||
} > runtime
|
|
||||||
|
|
||||||
.rodata :
|
.rodata :
|
||||||
{
|
{
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "kloader.h"
|
#include "kloader.h"
|
||||||
#include "flash_storage.h"
|
#include "flash_storage.h"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
|
#include "rtiocrg.h"
|
||||||
#include "test_mode.h"
|
#include "test_mode.h"
|
||||||
#include "kserver.h"
|
#include "kserver.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
|
@ -250,6 +251,7 @@ int main(void)
|
||||||
puts("ARTIQ runtime built "__DATE__" "__TIME__"\n");
|
puts("ARTIQ runtime built "__DATE__" "__TIME__"\n");
|
||||||
|
|
||||||
clock_init();
|
clock_init();
|
||||||
|
rtiocrg_init();
|
||||||
puts("Press 't' to enter test mode...");
|
puts("Press 't' to enter test mode...");
|
||||||
blink_led();
|
blink_led();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <generated/csr.h>
|
||||||
|
|
||||||
|
#include "clock.h"
|
||||||
|
#include "flash_storage.h"
|
||||||
|
#include "rtiocrg.h"
|
||||||
|
|
||||||
|
void rtiocrg_init(void)
|
||||||
|
{
|
||||||
|
char b;
|
||||||
|
int clk;
|
||||||
|
|
||||||
|
#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR
|
||||||
|
rtio_crg_pll_reset_write(0);
|
||||||
|
#endif
|
||||||
|
b = 'i';
|
||||||
|
clk = 0;
|
||||||
|
fs_read("startup_clock", &b, 1, NULL);
|
||||||
|
if(b == 'i')
|
||||||
|
printf("Startup RTIO clock: internal\n");
|
||||||
|
else if(b == 'e') {
|
||||||
|
printf("Startup RTIO clock: external\n");
|
||||||
|
clk = 1;
|
||||||
|
} else
|
||||||
|
printf("WARNING: unknown startup_clock entry in flash storage\n");
|
||||||
|
|
||||||
|
if(!rtiocrg_switch_clock(clk)) {
|
||||||
|
printf("WARNING: startup RTIO clock failed\n");
|
||||||
|
printf("WARNING: this may cause the system initialization to fail\n");
|
||||||
|
printf("WARNING: fix clocking and reset the device\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtiocrg_check(void)
|
||||||
|
{
|
||||||
|
#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR
|
||||||
|
return rtio_crg_pll_locked_read();
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtiocrg_switch_clock(int clk)
|
||||||
|
{
|
||||||
|
int current_clk;
|
||||||
|
|
||||||
|
current_clk = rtio_crg_clock_sel_read();
|
||||||
|
if(clk == current_clk) {
|
||||||
|
#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR
|
||||||
|
busywait_us(150);
|
||||||
|
if(!rtio_crg_pll_locked_read())
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR
|
||||||
|
rtio_crg_pll_reset_write(1);
|
||||||
|
#endif
|
||||||
|
rtio_crg_clock_sel_write(clk);
|
||||||
|
#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR
|
||||||
|
rtio_crg_pll_reset_write(0);
|
||||||
|
busywait_us(150);
|
||||||
|
if(!rtio_crg_pll_locked_read())
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef __RTIOCRG_H
|
||||||
|
#define __RTIOCRG_H
|
||||||
|
|
||||||
|
void rtiocrg_init(void);
|
||||||
|
int rtiocrg_check(void);
|
||||||
|
int rtiocrg_switch_clock(int clk);
|
||||||
|
|
||||||
|
#endif /* __RTIOCRG_H */
|
|
@ -12,6 +12,7 @@
|
||||||
#include "kloader.h"
|
#include "kloader.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "flash_storage.h"
|
#include "flash_storage.h"
|
||||||
|
#include "rtiocrg.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
|
|
||||||
#define BUFFER_IN_SIZE (1024*1024)
|
#define BUFFER_IN_SIZE (1024*1024)
|
||||||
|
@ -154,8 +155,10 @@ static int process_input(void)
|
||||||
submit_output(9);
|
submit_output(9);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rtio_crg_clock_sel_write(buffer_in[9]);
|
if(rtiocrg_switch_clock(buffer_in[9]))
|
||||||
buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_COMPLETED;
|
buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_COMPLETED;
|
||||||
|
else
|
||||||
|
buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_FAILED;
|
||||||
submit_output(9);
|
submit_output(9);
|
||||||
break;
|
break;
|
||||||
case REMOTEMSG_TYPE_LOAD_OBJECT:
|
case REMOTEMSG_TYPE_LOAD_OBJECT:
|
||||||
|
@ -527,11 +530,18 @@ void session_poll(void **data, int *len)
|
||||||
{
|
{
|
||||||
int l;
|
int l;
|
||||||
|
|
||||||
if((user_kernel_state == USER_KERNEL_RUNNING) && watchdog_expired()) {
|
if(user_kernel_state == USER_KERNEL_RUNNING) {
|
||||||
|
if(watchdog_expired()) {
|
||||||
log("Watchdog expired");
|
log("Watchdog expired");
|
||||||
*len = -1;
|
*len = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(!rtiocrg_check()) {
|
||||||
|
log("RTIO clock failure");
|
||||||
|
*len = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
l = get_out_packet_len();
|
l = get_out_packet_len();
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
from migen.fhdl.std import *
|
from migen.fhdl.std import *
|
||||||
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
|
from migen.genlib.cdc import MultiReg
|
||||||
from migen.bank.description import *
|
from migen.bank.description import *
|
||||||
from migen.bank import wbgen
|
from migen.bank import wbgen
|
||||||
from mibuild.generic_platform import *
|
from mibuild.generic_platform import *
|
||||||
from mibuild.xilinx.vivado import XilinxVivadoToolchain
|
from mibuild.xilinx.vivado import XilinxVivadoToolchain
|
||||||
|
from mibuild.xilinx.ise import XilinxISEToolchain
|
||||||
|
|
||||||
from misoclib.com import gpio
|
from misoclib.com import gpio
|
||||||
from misoclib.soc import mem_decoder
|
from misoclib.soc import mem_decoder
|
||||||
|
@ -11,13 +14,22 @@ from targets.kc705 import MiniSoC
|
||||||
|
|
||||||
from artiq.gateware.soc import AMPSoC
|
from artiq.gateware.soc import AMPSoC
|
||||||
from artiq.gateware import rtio, nist_qc1, nist_qc2
|
from artiq.gateware import rtio, nist_qc1, nist_qc2
|
||||||
from artiq.gateware.rtio.phy import ttl_simple, dds
|
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds
|
||||||
|
|
||||||
|
|
||||||
class _RTIOCRG(Module, AutoCSR):
|
class _RTIOCRG(Module, AutoCSR):
|
||||||
def __init__(self, platform, rtio_internal_clk):
|
def __init__(self, platform, rtio_internal_clk):
|
||||||
self._clock_sel = CSRStorage()
|
self._clock_sel = CSRStorage()
|
||||||
self.clock_domains.cd_rtio = ClockDomain(reset_less=True)
|
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)
|
||||||
|
|
||||||
|
# 10 MHz when using 125MHz input
|
||||||
|
self.clock_domains.cd_ext_clkout = ClockDomain(reset_less=True)
|
||||||
|
ext_clkout = platform.request("user_sma_gpio_p")
|
||||||
|
self.sync.ext_clkout += ext_clkout.eq(~ext_clkout)
|
||||||
|
|
||||||
|
|
||||||
rtio_external_clk = Signal()
|
rtio_external_clk = Signal()
|
||||||
user_sma_clock = platform.request("user_sma_clock")
|
user_sma_clock = platform.request("user_sma_clock")
|
||||||
|
@ -25,11 +37,40 @@ class _RTIOCRG(Module, AutoCSR):
|
||||||
self.specials += Instance("IBUFDS",
|
self.specials += Instance("IBUFDS",
|
||||||
i_I=user_sma_clock.p, i_IB=user_sma_clock.n,
|
i_I=user_sma_clock.p, i_IB=user_sma_clock.n,
|
||||||
o_O=rtio_external_clk)
|
o_O=rtio_external_clk)
|
||||||
self.specials += Instance("BUFGMUX",
|
|
||||||
i_I0=rtio_internal_clk,
|
pll_locked = Signal()
|
||||||
i_I1=rtio_external_clk,
|
rtio_clk = Signal()
|
||||||
i_S=self._clock_sel.storage,
|
rtiox4_clk = Signal()
|
||||||
o_O=self.cd_rtio.clk)
|
ext_clkout_clk = Signal()
|
||||||
|
self.specials += [
|
||||||
|
Instance("PLLE2_ADV",
|
||||||
|
p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
|
||||||
|
|
||||||
|
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,
|
||||||
|
# Warning: CLKINSEL=0 means CLKIN2 is selected
|
||||||
|
i_CLKINSEL=~self._clock_sel.storage,
|
||||||
|
|
||||||
|
# VCO @ 1GHz when using 125MHz input
|
||||||
|
p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1,
|
||||||
|
i_CLKFBIN=self.cd_rtio.clk,
|
||||||
|
i_RST=self._pll_reset.storage,
|
||||||
|
|
||||||
|
o_CLKFBOUT=rtio_clk,
|
||||||
|
|
||||||
|
p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0,
|
||||||
|
o_CLKOUT0=rtiox4_clk,
|
||||||
|
|
||||||
|
p_CLKOUT1_DIVIDE=50, p_CLKOUT1_PHASE=0.0,
|
||||||
|
o_CLKOUT1=ext_clkout_clk),
|
||||||
|
Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk),
|
||||||
|
Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk),
|
||||||
|
Instance("BUFG", i_I=ext_clkout_clk, o_O=self.cd_ext_clkout.clk),
|
||||||
|
|
||||||
|
AsyncResetSynchronizer(self.cd_rtio, ~pll_locked),
|
||||||
|
MultiReg(pll_locked, self._pll_locked.status)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class _NIST_QCx(MiniSoC, AMPSoC):
|
class _NIST_QCx(MiniSoC, AMPSoC):
|
||||||
|
@ -57,10 +98,10 @@ class _NIST_QCx(MiniSoC, AMPSoC):
|
||||||
platform.request("user_led", 1)))
|
platform.request("user_led", 1)))
|
||||||
|
|
||||||
def add_rtio(self, rtio_channels):
|
def add_rtio(self, rtio_channels):
|
||||||
self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.pll_sys)
|
self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk)
|
||||||
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
self.submodules.rtio = rtio.RTIO(rtio_channels)
|
||||||
clk_freq=125000000)
|
|
||||||
self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width)
|
self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width)
|
||||||
|
assert self.rtio.fine_ts_width <= 3
|
||||||
self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width)
|
self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width)
|
||||||
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
||||||
|
|
||||||
|
@ -71,6 +112,13 @@ create_clock -name rio_clk -period 8.0 [get_nets {rio_clk}]
|
||||||
set_false_path -from [get_clocks rsys_clk] -to [get_clocks rio_clk]
|
set_false_path -from [get_clocks rsys_clk] -to [get_clocks rio_clk]
|
||||||
set_false_path -from [get_clocks rio_clk] -to [get_clocks rsys_clk]
|
set_false_path -from [get_clocks rio_clk] -to [get_clocks rsys_clk]
|
||||||
""", rsys_clk=self.rtio.cd_rsys.clk, rio_clk=self.rtio.cd_rio.clk)
|
""", rsys_clk=self.rtio.cd_rsys.clk, rio_clk=self.rtio.cd_rio.clk)
|
||||||
|
if isinstance(self.platform.toolchain, XilinxISEToolchain):
|
||||||
|
self.platform.add_platform_command("""
|
||||||
|
NET "sys_clk" TNM_NET = "GRPrsys_clk";
|
||||||
|
NET "{rio_clk}" TNM_NET = "GRPrio_clk";
|
||||||
|
TIMESPEC "TSfix_cdc1" = FROM "GRPrsys_clk" TO "GRPrio_clk" TIG;
|
||||||
|
TIMESPEC "TSfix_cdc2" = FROM "GRPrio_clk" TO "GRPrsys_clk" TIG;
|
||||||
|
""", rio_clk=self.rtio_crg.cd_rtio.clk)
|
||||||
|
|
||||||
rtio_csrs = self.rtio.get_csrs()
|
rtio_csrs = self.rtio.get_csrs()
|
||||||
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
|
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
|
||||||
|
@ -92,11 +140,11 @@ class NIST_QC1(_NIST_QCx):
|
||||||
|
|
||||||
rtio_channels = []
|
rtio_channels = []
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
phy = ttl_simple.Inout(platform.request("pmt", i))
|
phy = ttl_serdes_7series.Inout_8X(platform.request("pmt", i))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512))
|
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512))
|
||||||
for i in range(15):
|
for i in range(15):
|
||||||
phy = ttl_simple.Output(platform.request("ttl", i))
|
phy = ttl_serdes_7series.Output_8X(platform.request("ttl", i))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
|
@ -131,11 +179,11 @@ class NIST_QC2(_NIST_QCx):
|
||||||
# TTL14 is for the clock generator
|
# TTL14 is for the clock generator
|
||||||
continue
|
continue
|
||||||
if i % 4 == 3:
|
if i % 4 == 3:
|
||||||
phy = ttl_simple.Inout(platform.request("ttl", i))
|
phy = ttl_serdes_7series.Inout_8X(platform.request("ttl", i))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512))
|
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512))
|
||||||
else:
|
else:
|
||||||
phy = ttl_simple.Output(platform.request("ttl", i))
|
phy = ttl_serdes_7series.Output_8X(platform.request("ttl", i))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ 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.bank import wbgen
|
from migen.bank import wbgen
|
||||||
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
|
from migen.genlib.cdc import MultiReg
|
||||||
|
|
||||||
from misoclib.com import gpio
|
from misoclib.com import gpio
|
||||||
from misoclib.soc import mem_decoder
|
from misoclib.soc import mem_decoder
|
||||||
|
@ -11,46 +13,84 @@ from targets.pipistrello import BaseSoC
|
||||||
|
|
||||||
from artiq.gateware.soc import AMPSoC
|
from artiq.gateware.soc import AMPSoC
|
||||||
from artiq.gateware import rtio, nist_qc1
|
from artiq.gateware import rtio, nist_qc1
|
||||||
from artiq.gateware.rtio.phy import ttl_simple, dds
|
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_spartan6, dds
|
||||||
|
|
||||||
|
|
||||||
class _RTIOCRG(Module, AutoCSR):
|
class _RTIOCRG(Module, AutoCSR):
|
||||||
def __init__(self, platform, clk_freq):
|
def __init__(self, platform, clk_freq):
|
||||||
self._clock_sel = CSRStorage()
|
self._clock_sel = CSRStorage()
|
||||||
self.clock_domains.cd_rtio = ClockDomain(reset_less=True)
|
self._pll_reset = CSRStorage(reset=1)
|
||||||
|
self._pll_locked = CSRStatus()
|
||||||
|
|
||||||
f = Fraction(125*1000*1000, clk_freq)
|
self.clock_domains.cd_rtio = ClockDomain()
|
||||||
|
self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True)
|
||||||
|
self.clock_domains.cd_rtiox8 = ClockDomain(reset_less=True)
|
||||||
|
self.rtiox4_stb = Signal()
|
||||||
|
self.rtiox8_stb = Signal()
|
||||||
|
|
||||||
|
rtio_f = 125*1000*1000
|
||||||
|
f = Fraction(rtio_f, clk_freq)
|
||||||
rtio_internal_clk = Signal()
|
rtio_internal_clk = Signal()
|
||||||
self.specials += Instance("DCM_CLKGEN",
|
rtio_external_clk = Signal()
|
||||||
p_CLKFXDV_DIVIDE=2,
|
pmt2 = platform.request("pmt", 2)
|
||||||
p_CLKFX_DIVIDE=f.denominator,
|
dcm_locked = Signal()
|
||||||
p_CLKFX_MD_MAX=float(f),
|
rtio_clk = Signal()
|
||||||
p_CLKFX_MULTIPLY=f.numerator,
|
pll_locked = Signal()
|
||||||
p_CLKIN_PERIOD=1e9/clk_freq,
|
pll = Signal(3)
|
||||||
p_SPREAD_SPECTRUM="NONE",
|
pll_fb = Signal()
|
||||||
p_STARTUP_WAIT="FALSE",
|
self.specials += [
|
||||||
i_CLKIN=ClockSignal(),
|
Instance("IBUFG", i_I=pmt2, o_O=rtio_external_clk),
|
||||||
o_CLKFX=rtio_internal_clk,
|
Instance("DCM_CLKGEN", p_CLKFXDV_DIVIDE=2,
|
||||||
i_FREEZEDCM=0,
|
p_CLKFX_DIVIDE=f.denominator, p_CLKFX_MD_MAX=float(f),
|
||||||
i_RST=ResetSignal())
|
p_CLKFX_MULTIPLY=f.numerator, p_CLKIN_PERIOD=1e9/clk_freq,
|
||||||
|
p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE",
|
||||||
rtio_external_clk = platform.request("pmt", 2)
|
i_CLKIN=ClockSignal(), o_CLKFX=rtio_internal_clk,
|
||||||
# ISE infers constraints for the internal clock
|
i_FREEZEDCM=0, i_RST=ResetSignal(), o_LOCKED=dcm_locked),
|
||||||
# and propagates them through the BUFGMUX. Adding this:
|
Instance("BUFGMUX",
|
||||||
# platform.add_period_constraint(rtio_external_clk, 8.0)
|
i_I0=rtio_internal_clk, i_I1=rtio_external_clk,
|
||||||
# seems to confuse it
|
i_S=self._clock_sel.storage, o_O=rtio_clk),
|
||||||
self.specials += Instance("BUFGMUX",
|
Instance("PLL_ADV", p_SIM_DEVICE="SPARTAN6",
|
||||||
i_I0=rtio_internal_clk,
|
p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL",
|
||||||
i_I1=rtio_external_clk,
|
p_REF_JITTER=.01, p_CLK_FEEDBACK="CLKFBOUT",
|
||||||
i_S=self._clock_sel.storage,
|
i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0,
|
||||||
o_O=self.cd_rtio.clk)
|
i_RST=self._pll_reset.storage | ~dcm_locked, i_REL=0,
|
||||||
|
p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=8,
|
||||||
|
p_CLKFBOUT_PHASE=0., i_CLKINSEL=1,
|
||||||
|
i_CLKIN1=rtio_clk, i_CLKIN2=0,
|
||||||
|
p_CLKIN1_PERIOD=1e9/rtio_f, p_CLKIN2_PERIOD=0.,
|
||||||
|
i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_locked,
|
||||||
|
o_CLKOUT0=pll[0], p_CLKOUT0_DUTY_CYCLE=.5,
|
||||||
|
o_CLKOUT1=pll[1], p_CLKOUT1_DUTY_CYCLE=.5,
|
||||||
|
o_CLKOUT2=pll[2], p_CLKOUT2_DUTY_CYCLE=.5,
|
||||||
|
p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=1,
|
||||||
|
p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=2,
|
||||||
|
p_CLKOUT2_PHASE=0., p_CLKOUT2_DIVIDE=8),
|
||||||
|
Instance("BUFPLL", p_DIVIDE=8,
|
||||||
|
i_PLLIN=pll[0], i_GCLK=self.cd_rtio.clk,
|
||||||
|
i_LOCKED=pll_locked, o_IOCLK=self.cd_rtiox8.clk,
|
||||||
|
o_SERDESSTROBE=self.rtiox8_stb),
|
||||||
|
Instance("BUFPLL", p_DIVIDE=4,
|
||||||
|
i_PLLIN=pll[1], i_GCLK=self.cd_rtio.clk,
|
||||||
|
i_LOCKED=pll_locked, o_IOCLK=self.cd_rtiox4.clk,
|
||||||
|
o_SERDESSTROBE=self.rtiox4_stb),
|
||||||
|
Instance("BUFG", i_I=pll[2], o_O=self.cd_rtio.clk),
|
||||||
|
AsyncResetSynchronizer(self.cd_rtio, ~pll_locked),
|
||||||
|
MultiReg(pll_locked, self._pll_locked.status),
|
||||||
|
]
|
||||||
|
|
||||||
|
# ISE infers correct period constraints for cd_rtio.clk from
|
||||||
|
# the internal clock. The first two TIGs target just the BUFGMUX.
|
||||||
platform.add_platform_command("""
|
platform.add_platform_command("""
|
||||||
NET "{int_clk}" TNM_NET = "GRPint_clk";
|
|
||||||
NET "sys_clk" TNM_NET = "GRPsys_clk";
|
NET "sys_clk" TNM_NET = "GRPsys_clk";
|
||||||
TIMESPEC "TSfix_ise1" = FROM "GRPint_clk" TO "GRPsys_clk" TIG;
|
NET "{ext_clk}" TNM_NET = "GRPext_clk";
|
||||||
|
TIMESPEC "TSfix_ise1" = FROM "GRPsys_clk" TO "GRPext_clk" TIG;
|
||||||
|
NET "{int_clk}" TNM_NET = "GRPint_clk";
|
||||||
TIMESPEC "TSfix_ise2" = FROM "GRPsys_clk" TO "GRPint_clk" TIG;
|
TIMESPEC "TSfix_ise2" = FROM "GRPsys_clk" TO "GRPint_clk" TIG;
|
||||||
""", int_clk=rtio_internal_clk)
|
NET "{rtio_clk}" TNM_NET = "GRPrtio_clk";
|
||||||
|
TIMESPEC "TSfix_ise3" = FROM "GRPrtio_clk" TO "GRPsys_clk" TIG;
|
||||||
|
TIMESPEC "TSfix_ise4" = FROM "GRPsys_clk" TO "GRPrtio_clk" TIG;
|
||||||
|
""", ext_clk=rtio_external_clk, int_clk=rtio_internal_clk,
|
||||||
|
rtio_clk=self.cd_rtio.clk)
|
||||||
|
|
||||||
|
|
||||||
class NIST_QC1(BaseSoC, AMPSoC):
|
class NIST_QC1(BaseSoC, AMPSoC):
|
||||||
|
@ -73,6 +113,7 @@ class NIST_QC1(BaseSoC, AMPSoC):
|
||||||
sdram_controller_settings=MiniconSettings(l2_size=64*1024),
|
sdram_controller_settings=MiniconSettings(l2_size=64*1024),
|
||||||
with_timer=False, **kwargs)
|
with_timer=False, **kwargs)
|
||||||
AMPSoC.__init__(self)
|
AMPSoC.__init__(self)
|
||||||
|
platform.toolchain.bitgen_opt = "-g Binary:Yes -w"
|
||||||
platform.toolchain.ise_commands += """
|
platform.toolchain.ise_commands += """
|
||||||
trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd {build_name}.pcf
|
trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd {build_name}.pcf
|
||||||
"""
|
"""
|
||||||
|
@ -90,16 +131,29 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
|
||||||
platform.request("ttl_h_tx_en").eq(1)
|
platform.request("ttl_h_tx_en").eq(1)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq)
|
||||||
|
|
||||||
# RTIO channels
|
# RTIO channels
|
||||||
rtio_channels = []
|
rtio_channels = []
|
||||||
|
# pmt1 can run on a 8x serdes if pmt0 is not used
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
phy = ttl_simple.Inout(platform.request("pmt", i))
|
phy = ttl_serdes_spartan6.Inout_4X(platform.request("pmt", i),
|
||||||
|
self.rtio_crg.rtiox4_stb)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512,
|
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512,
|
||||||
ofifo_depth=4))
|
ofifo_depth=4))
|
||||||
|
|
||||||
|
# ttl2 can run on a 8x serdes if xtrig is not used
|
||||||
for i in range(15):
|
for i in range(15):
|
||||||
|
if i in (0, 1):
|
||||||
|
phy = ttl_serdes_spartan6.Output_4X(platform.request("ttl", i),
|
||||||
|
self.rtio_crg.rtiox4_stb)
|
||||||
|
elif i in (2,):
|
||||||
|
phy = ttl_serdes_spartan6.Output_8X(platform.request("ttl", i),
|
||||||
|
self.rtio_crg.rtiox8_stb)
|
||||||
|
else:
|
||||||
phy = ttl_simple.Output(platform.request("ttl", i))
|
phy = ttl_simple.Output(platform.request("ttl", i))
|
||||||
|
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=256))
|
rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=256))
|
||||||
|
|
||||||
|
@ -120,16 +174,16 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
|
||||||
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
||||||
self.add_constant("DDS_CHANNEL_COUNT", 8)
|
self.add_constant("DDS_CHANNEL_COUNT", 8)
|
||||||
self.add_constant("DDS_AD9858")
|
self.add_constant("DDS_AD9858")
|
||||||
phy = dds.AD9858(platform.request("dds"), 8)
|
dds_pins = platform.request("dds")
|
||||||
|
self.comb += dds_pins.p.eq(0)
|
||||||
|
phy = dds.AD9858(dds_pins, 8)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy,
|
rtio_channels.append(rtio.Channel.from_phy(phy,
|
||||||
ofifo_depth=512,
|
ofifo_depth=512,
|
||||||
ififo_depth=4))
|
ififo_depth=4))
|
||||||
|
|
||||||
# RTIO core
|
# RTIO core
|
||||||
self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq)
|
self.submodules.rtio = rtio.RTIO(rtio_channels)
|
||||||
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
|
||||||
clk_freq=125000000)
|
|
||||||
self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width)
|
self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width)
|
||||||
self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width)
|
self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width)
|
||||||
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
||||||
|
|
Loading…
Reference in New Issue