forked from M-Labs/artiq
soc,runtime: support TTL override
This commit is contained in:
parent
6c094b500d
commit
b2af0f6cc3
|
@ -1,2 +1,2 @@
|
||||||
from artiq.gateware.rtio.core import Channel, RTIO
|
from artiq.gateware.rtio.core import Channel, RTIO
|
||||||
from artiq.gateware.rtio.moninj import Monitor
|
from artiq.gateware.rtio.moninj import MonInj
|
||||||
|
|
|
@ -247,12 +247,20 @@ class _InputManager(Module):
|
||||||
|
|
||||||
|
|
||||||
class Channel:
|
class Channel:
|
||||||
def __init__(self, interface, probes=[], ofifo_depth=64, ififo_depth=64):
|
def __init__(self, interface, probes=[], overrides=[],
|
||||||
|
ofifo_depth=64, ififo_depth=64):
|
||||||
self.interface = interface
|
self.interface = interface
|
||||||
self.probes = probes
|
self.probes = probes
|
||||||
|
self.overrides = overrides
|
||||||
self.ofifo_depth = ofifo_depth
|
self.ofifo_depth = ofifo_depth
|
||||||
self.ififo_depth = ififo_depth
|
self.ififo_depth = ififo_depth
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_phy(cls, phy, **kwargs):
|
||||||
|
probes = getattr(phy, "probes", [])
|
||||||
|
overrides = getattr(phy, "overrides", [])
|
||||||
|
return cls(phy.rtlink, probes, overrides, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class _KernelCSRs(AutoCSR):
|
class _KernelCSRs(AutoCSR):
|
||||||
def __init__(self, chan_sel_width,
|
def __init__(self, chan_sel_width,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from migen.fhdl.std import *
|
from migen.fhdl.std import *
|
||||||
from migen.bank.description import *
|
from migen.bank.description import *
|
||||||
from migen.genlib.cdc import BusSynchronizer
|
from migen.genlib.cdc import BusSynchronizer, MultiReg
|
||||||
|
|
||||||
|
|
||||||
class Monitor(Module, AutoCSR):
|
class Monitor(Module, AutoCSR):
|
||||||
|
@ -11,7 +11,7 @@ class Monitor(Module, AutoCSR):
|
||||||
max_probe_len = max(flen(p) for cp in chan_probes for p in cp)
|
max_probe_len = max(flen(p) for cp in chan_probes for p in cp)
|
||||||
self.chan_sel = CSRStorage(bits_for(len(chan_probes)-1))
|
self.chan_sel = CSRStorage(bits_for(len(chan_probes)-1))
|
||||||
self.probe_sel = CSRStorage(bits_for(max_chan_probes-1))
|
self.probe_sel = CSRStorage(bits_for(max_chan_probes-1))
|
||||||
self.probe_value = CSRStatus(max_probe_len)
|
self.value = CSRStatus(max_probe_len)
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
|
@ -25,5 +25,42 @@ class Monitor(Module, AutoCSR):
|
||||||
cp_sys.append(vs.o)
|
cp_sys.append(vs.o)
|
||||||
cp_sys += [0]*(max_chan_probes-len(cp))
|
cp_sys += [0]*(max_chan_probes-len(cp))
|
||||||
chan_probes_sys.append(Array(cp_sys)[self.probe_sel.storage])
|
chan_probes_sys.append(Array(cp_sys)[self.probe_sel.storage])
|
||||||
self.comb += self.probe_value.status.eq(
|
self.comb += self.value.status.eq(
|
||||||
Array(chan_probes_sys)[self.chan_sel.storage])
|
Array(chan_probes_sys)[self.chan_sel.storage])
|
||||||
|
|
||||||
|
|
||||||
|
class Injector(Module, AutoCSR):
|
||||||
|
def __init__(self, channels):
|
||||||
|
chan_overrides = [c.overrides for c in channels]
|
||||||
|
|
||||||
|
max_chan_overrides = max(len(co) for co in chan_overrides)
|
||||||
|
max_override_len = max(flen(o) for co in chan_overrides for o in co)
|
||||||
|
self.chan_sel = CSRStorage(bits_for(len(chan_overrides)-1))
|
||||||
|
self.override_sel = CSRStorage(bits_for(max_chan_overrides-1))
|
||||||
|
self.value = CSR(max_override_len)
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
chan_overrides_sys = []
|
||||||
|
for n_channel, co in enumerate(chan_overrides):
|
||||||
|
co_sys = []
|
||||||
|
for n_override, o in enumerate(co):
|
||||||
|
# We do the clock domain transfer with a simple double-latch.
|
||||||
|
# Software has to ensure proper timing of any strobe signal etc.
|
||||||
|
# to avoid problematic glitches.
|
||||||
|
o_sys = Signal.like(o)
|
||||||
|
self.specials += MultiReg(o_sys, o, "rio")
|
||||||
|
self.sync += If(self.value.re & (self.chan_sel.storage == n_channel)
|
||||||
|
& (self.override_sel.storage == n_override),
|
||||||
|
o_sys.eq(self.value.r))
|
||||||
|
co_sys.append(o_sys)
|
||||||
|
co_sys += [0]*(max_chan_overrides-len(co))
|
||||||
|
chan_overrides_sys.append(Array(co_sys)[self.override_sel.storage])
|
||||||
|
self.comb += self.value.w.eq(
|
||||||
|
Array(chan_overrides_sys)[self.chan_sel.storage])
|
||||||
|
|
||||||
|
|
||||||
|
class MonInj(Module, AutoCSR):
|
||||||
|
def __init__(self, channels):
|
||||||
|
self.submodules.mon = Monitor(channels)
|
||||||
|
self.submodules.inj = Injector(channels)
|
||||||
|
|
|
@ -8,10 +8,23 @@ class Output(Module):
|
||||||
def __init__(self, pad):
|
def __init__(self, pad):
|
||||||
self.rtlink = rtlink.Interface(rtlink.OInterface(1))
|
self.rtlink = rtlink.Interface(rtlink.OInterface(1))
|
||||||
self.probes = [pad]
|
self.probes = [pad]
|
||||||
|
override_en = Signal()
|
||||||
|
override_o = Signal()
|
||||||
|
self.overrides = [override_en, override_o]
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
self.sync.rio_phy += If(self.rtlink.o.stb, pad.eq(self.rtlink.o.data))
|
pad_k = Signal()
|
||||||
|
self.sync.rio_phy += [
|
||||||
|
If(self.rtlink.o.stb,
|
||||||
|
pad_k.eq(self.rtlink.o.data)
|
||||||
|
),
|
||||||
|
If(override_en,
|
||||||
|
pad.eq(override_o)
|
||||||
|
).Else(
|
||||||
|
pad.eq(pad_k)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class Inout(Module):
|
class Inout(Module):
|
||||||
|
@ -19,6 +32,10 @@ class Inout(Module):
|
||||||
self.rtlink = rtlink.Interface(
|
self.rtlink = rtlink.Interface(
|
||||||
rtlink.OInterface(2, 2),
|
rtlink.OInterface(2, 2),
|
||||||
rtlink.IInterface(1))
|
rtlink.IInterface(1))
|
||||||
|
override_en = Signal()
|
||||||
|
override_o = Signal()
|
||||||
|
override_oe = Signal()
|
||||||
|
self.overrides = [override_en, override_o, override_oe]
|
||||||
self.probes = []
|
self.probes = []
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
@ -27,10 +44,21 @@ class Inout(Module):
|
||||||
self.specials += ts.get_tristate(pad)
|
self.specials += ts.get_tristate(pad)
|
||||||
sensitivity = Signal(2)
|
sensitivity = Signal(2)
|
||||||
|
|
||||||
self.sync.rio_phy += If(self.rtlink.o.stb,
|
o_k = Signal()
|
||||||
If(self.rtlink.o.address == 0, ts.o.eq(self.rtlink.o.data[0])),
|
oe_k = Signal()
|
||||||
If(self.rtlink.o.address == 1, ts.oe.eq(self.rtlink.o.data[0])),
|
self.sync.rio_phy += [
|
||||||
|
If(self.rtlink.o.stb,
|
||||||
|
If(self.rtlink.o.address == 0, o_k.eq(self.rtlink.o.data[0])),
|
||||||
|
If(self.rtlink.o.address == 1, oe_k.eq(self.rtlink.o.data[0])),
|
||||||
|
),
|
||||||
|
If(override_en,
|
||||||
|
ts.o.eq(override_o),
|
||||||
|
ts.oe.eq(override_oe)
|
||||||
|
).Else(
|
||||||
|
ts.o.eq(o_k),
|
||||||
|
ts.oe.eq(oe_k)
|
||||||
)
|
)
|
||||||
|
]
|
||||||
self.sync.rio += If(self.rtlink.o.stb & (self.rtlink.o.address == 2),
|
self.sync.rio += If(self.rtlink.o.stb & (self.rtlink.o.address == 2),
|
||||||
sensitivity.eq(self.rtlink.o.data))
|
sensitivity.eq(self.rtlink.o.data))
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,19 @@ enum {
|
||||||
MONINJ_REQ_TTLSET = 2
|
MONINJ_REQ_TTLSET = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MONINJ_TTL_MODE_EXP = 0,
|
||||||
|
MONINJ_TTL_MODE_1 = 1,
|
||||||
|
MONINJ_TTL_MODE_0 = 2,
|
||||||
|
MONINJ_TTL_MODE_IN = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MONINJ_TTL_OVERRIDE_ENABLE = 0,
|
||||||
|
MONINJ_TTL_OVERRIDE_O = 1,
|
||||||
|
MONINJ_TTL_OVERRIDE_OE = 2
|
||||||
|
};
|
||||||
|
|
||||||
static struct udp_pcb *listen_pcb;
|
static struct udp_pcb *listen_pcb;
|
||||||
|
|
||||||
struct monitor_reply {
|
struct monitor_reply {
|
||||||
|
@ -28,8 +41,6 @@ struct monitor_reply {
|
||||||
long long int ttl_overrides;
|
long long int ttl_overrides;
|
||||||
};
|
};
|
||||||
|
|
||||||
static long long int ttl_overrides;
|
|
||||||
|
|
||||||
static void moninj_monitor(const ip_addr_t *addr, u16_t port)
|
static void moninj_monitor(const ip_addr_t *addr, u16_t port)
|
||||||
{
|
{
|
||||||
struct monitor_reply reply;
|
struct monitor_reply reply;
|
||||||
|
@ -38,16 +49,20 @@ static void moninj_monitor(const ip_addr_t *addr, u16_t port)
|
||||||
|
|
||||||
reply.ttl_levels = 0;
|
reply.ttl_levels = 0;
|
||||||
reply.ttl_oes = 0;
|
reply.ttl_oes = 0;
|
||||||
|
reply.ttl_overrides = 0;
|
||||||
for(i=0;i<RTIO_TTL_COUNT;i++) {
|
for(i=0;i<RTIO_TTL_COUNT;i++) {
|
||||||
rtio_mon_chan_sel_write(i);
|
rtio_moninj_mon_chan_sel_write(i);
|
||||||
rtio_mon_probe_sel_write(0);
|
rtio_moninj_mon_probe_sel_write(0);
|
||||||
if(rtio_mon_probe_value_read())
|
if(rtio_moninj_mon_value_read())
|
||||||
reply.ttl_levels |= 1LL << i;
|
reply.ttl_levels |= 1LL << i;
|
||||||
rtio_mon_probe_sel_write(1);
|
rtio_moninj_mon_probe_sel_write(1);
|
||||||
if(rtio_mon_probe_value_read())
|
if(rtio_moninj_mon_value_read())
|
||||||
reply.ttl_oes |= 1LL << i;
|
reply.ttl_oes |= 1LL << i;
|
||||||
|
rtio_moninj_inj_chan_sel_write(i);
|
||||||
|
rtio_moninj_inj_override_sel_write(MONINJ_TTL_OVERRIDE_ENABLE);
|
||||||
|
if(rtio_moninj_inj_value_read())
|
||||||
|
reply.ttl_overrides |= 1LL << i;
|
||||||
}
|
}
|
||||||
reply.ttl_overrides = ttl_overrides;
|
|
||||||
|
|
||||||
reply_p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct monitor_reply), PBUF_RAM);
|
reply_p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct monitor_reply), PBUF_RAM);
|
||||||
if(!reply_p) {
|
if(!reply_p) {
|
||||||
|
@ -61,10 +76,38 @@ static void moninj_monitor(const ip_addr_t *addr, u16_t port)
|
||||||
|
|
||||||
static void moninj_ttlset(int channel, int mode)
|
static void moninj_ttlset(int channel, int mode)
|
||||||
{
|
{
|
||||||
if(mode)
|
rtio_moninj_inj_chan_sel_write(channel);
|
||||||
ttl_overrides |= (1LL << channel);
|
switch(mode) {
|
||||||
else
|
case MONINJ_TTL_MODE_EXP:
|
||||||
ttl_overrides &= ~(1LL << channel);
|
rtio_moninj_inj_override_sel_write(MONINJ_TTL_OVERRIDE_ENABLE);
|
||||||
|
rtio_moninj_inj_value_write(0);
|
||||||
|
break;
|
||||||
|
case MONINJ_TTL_MODE_1:
|
||||||
|
rtio_moninj_inj_override_sel_write(MONINJ_TTL_OVERRIDE_O);
|
||||||
|
rtio_moninj_inj_value_write(1);
|
||||||
|
rtio_moninj_inj_override_sel_write(MONINJ_TTL_OVERRIDE_OE);
|
||||||
|
rtio_moninj_inj_value_write(1);
|
||||||
|
rtio_moninj_inj_override_sel_write(MONINJ_TTL_OVERRIDE_ENABLE);
|
||||||
|
rtio_moninj_inj_value_write(1);
|
||||||
|
break;
|
||||||
|
case MONINJ_TTL_MODE_0:
|
||||||
|
rtio_moninj_inj_override_sel_write(MONINJ_TTL_OVERRIDE_O);
|
||||||
|
rtio_moninj_inj_value_write(0);
|
||||||
|
rtio_moninj_inj_override_sel_write(MONINJ_TTL_OVERRIDE_OE);
|
||||||
|
rtio_moninj_inj_value_write(1);
|
||||||
|
rtio_moninj_inj_override_sel_write(MONINJ_TTL_OVERRIDE_ENABLE);
|
||||||
|
rtio_moninj_inj_value_write(1);
|
||||||
|
break;
|
||||||
|
case MONINJ_TTL_MODE_IN:
|
||||||
|
rtio_moninj_inj_override_sel_write(MONINJ_TTL_OVERRIDE_OE);
|
||||||
|
rtio_moninj_inj_value_write(0);
|
||||||
|
rtio_moninj_inj_override_sel_write(MONINJ_TTL_OVERRIDE_ENABLE);
|
||||||
|
rtio_moninj_inj_value_write(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log("unknown TTL mode %d", mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void moninj_recv(void *arg, struct udp_pcb *upcb, struct pbuf *req,
|
static void moninj_recv(void *arg, struct udp_pcb *upcb, struct pbuf *req,
|
||||||
|
|
|
@ -37,7 +37,7 @@ class NIST_QC1(MiniSoC, AMPSoC):
|
||||||
"rtio": None, # mapped on Wishbone instead
|
"rtio": None, # mapped on Wishbone instead
|
||||||
"rtio_crg": 13,
|
"rtio_crg": 13,
|
||||||
"kernel_cpu": 14,
|
"kernel_cpu": 14,
|
||||||
"rtio_mon": 15
|
"rtio_moninj": 15
|
||||||
}
|
}
|
||||||
csr_map.update(MiniSoC.csr_map)
|
csr_map.update(MiniSoC.csr_map)
|
||||||
mem_map = {
|
mem_map = {
|
||||||
|
@ -66,16 +66,15 @@ class NIST_QC1(MiniSoC, AMPSoC):
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
phy = ttl_simple.Inout(platform.request("pmt", i))
|
phy = ttl_simple.Inout(platform.request("pmt", i))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink, phy.probes,
|
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512))
|
||||||
ififo_depth=512))
|
|
||||||
for i in range(16):
|
for i in range(16):
|
||||||
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(phy.rtlink, phy.probes))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
phy = ttl_simple.Output(platform.request("user_led", 2))
|
phy = ttl_simple.Output(platform.request("user_led", 2))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink, phy.probes))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
self.add_constant("RTIO_TTL_COUNT", len(rtio_channels))
|
self.add_constant("RTIO_TTL_COUNT", len(rtio_channels))
|
||||||
|
|
||||||
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
||||||
|
@ -84,14 +83,14 @@ class NIST_QC1(MiniSoC, AMPSoC):
|
||||||
"rio")
|
"rio")
|
||||||
phy = RT2WB(7, self.dds.bus)
|
phy = RT2WB(7, self.dds.bus)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=4))
|
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))
|
||||||
|
|
||||||
# RTIO core
|
# RTIO core
|
||||||
self.submodules.rtio_crg = _RTIOCRG(platform, self.crg.pll_sys)
|
self.submodules.rtio_crg = _RTIOCRG(platform, self.crg.pll_sys)
|
||||||
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
||||||
clk_freq=125000000)
|
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.submodules.rtio_mon = rtio.Monitor(rtio_channels)
|
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
||||||
|
|
||||||
if isinstance(platform.toolchain, XilinxVivadoToolchain):
|
if isinstance(platform.toolchain, XilinxVivadoToolchain):
|
||||||
platform.add_platform_command("""
|
platform.add_platform_command("""
|
||||||
|
|
|
@ -91,26 +91,25 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
phy = ttl_simple.Inout(platform.request("pmt", i))
|
phy = ttl_simple.Inout(platform.request("pmt", i))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink, phy.probes,
|
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512))
|
||||||
ififo_depth=512))
|
|
||||||
|
|
||||||
phy = ttl_simple.Inout(platform.request("xtrig", 0))
|
phy = ttl_simple.Inout(platform.request("xtrig", 0))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink, phy.probes))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
for i in range(16):
|
for i in range(16):
|
||||||
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(phy.rtlink, phy.probes))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
phy = ttl_simple.Output(platform.request("ext_led", 0))
|
phy = ttl_simple.Output(platform.request("ext_led", 0))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink, phy.probes))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
for i in range(2, 5):
|
for i in range(2, 5):
|
||||||
phy = ttl_simple.Output(platform.request("user_led", i))
|
phy = ttl_simple.Output(platform.request("user_led", i))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink, phy.probes))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
self.add_constant("RTIO_TTL_COUNT", len(rtio_channels))
|
self.add_constant("RTIO_TTL_COUNT", len(rtio_channels))
|
||||||
|
|
||||||
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
||||||
|
@ -119,14 +118,14 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
|
||||||
"rio")
|
"rio")
|
||||||
phy = RT2WB(7, self.dds.bus)
|
phy = RT2WB(7, self.dds.bus)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=4))
|
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))
|
||||||
|
|
||||||
# RTIO core
|
# RTIO core
|
||||||
self.submodules.rtio_crg = _RTIOCRG(platform)
|
self.submodules.rtio_crg = _RTIOCRG(platform)
|
||||||
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
||||||
clk_freq=125000000)
|
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.submodules.rtio_mon = rtio.Monitor(rtio_channels)
|
self.submodules.rtio_mon = rtio.MonInj(rtio_channels)
|
||||||
|
|
||||||
# CPU connections
|
# CPU connections
|
||||||
rtio_csrs = self.rtio.get_csrs()
|
rtio_csrs = self.rtio.get_csrs()
|
||||||
|
|
Loading…
Reference in New Issue