forked from M-Labs/artiq
rtio/ttl_serdes: cleanup/rewrite
This commit is contained in:
parent
d90dff4ef1
commit
940aa815dd
|
@ -1,58 +1,70 @@
|
||||||
from migen.fhdl.std import *
|
from migen.fhdl.std import *
|
||||||
|
|
||||||
from artiq.gateware.rtio.phy import ttl_serdes_generic
|
from artiq.gateware.rtio.phy import ttl_serdes_generic
|
||||||
|
|
||||||
|
|
||||||
class OSerdese2(Module):
|
class _OSERDESE2_8X(Module):
|
||||||
def __init__(self, pad):
|
def __init__(self, pad):
|
||||||
self.o = o = Signal(8)
|
self.o = Signal(8)
|
||||||
self.oe = oe = Signal()
|
self.t_in = Signal()
|
||||||
self.t = t = Signal()
|
self.t_out = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
o = self.o
|
||||||
self.specials += Instance("OSERDESE2", p_DATA_RATE_OQ="DDR",
|
self.specials += Instance("OSERDESE2", p_DATA_RATE_OQ="DDR",
|
||||||
p_DATA_RATE_TQ="DDR", p_DATA_WIDTH=8,
|
p_DATA_RATE_TQ="DDR", p_DATA_WIDTH=8,
|
||||||
p_TRISTATE_WIDTH=1, o_OQ=pad, o_TQ=t,
|
p_TRISTATE_WIDTH=1,
|
||||||
|
o_OQ=pad, o_TQ=self.t_out,
|
||||||
i_CLK=ClockSignal("rtiox4"),
|
i_CLK=ClockSignal("rtiox4"),
|
||||||
i_CLKDIV=ClockSignal("rio_phy"),
|
i_CLKDIV=ClockSignal("rio_phy"),
|
||||||
i_D1=o[0], i_D2=o[1], i_D3=o[2], i_D4=o[3],
|
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_D5=o[4], i_D6=o[5], i_D7=o[6], i_D8=o[7],
|
||||||
i_TCE=1, i_OCE=1, i_RST=ResetSignal(),
|
i_TCE=1, i_OCE=1, i_RST=0,
|
||||||
i_T1=~oe)
|
i_T1=self.t_in)
|
||||||
|
|
||||||
|
|
||||||
class IOSerdese2(Module):
|
class _IOSERDESE2_8X(Module):
|
||||||
def __init__(self, pad):
|
def __init__(self, pad):
|
||||||
ts = TSTriple()
|
self.o = Signal(8)
|
||||||
self.o = o = Signal(8)
|
self.i = Signal(8)
|
||||||
self.oe = oe = Signal()
|
self.oe = Signal()
|
||||||
self.i = i = Signal(8)
|
|
||||||
self.specials += ts.get_tristate(pad)
|
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
pad_i = Signal()
|
||||||
|
pad_o = Signal()
|
||||||
|
i = self.i
|
||||||
self.specials += Instance("ISERDESE2", p_DATA_RATE="DDR",
|
self.specials += Instance("ISERDESE2", p_DATA_RATE="DDR",
|
||||||
p_DATA_WIDTH=8,
|
p_DATA_WIDTH=8,
|
||||||
p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1,
|
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_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],
|
o_Q5=i[3], o_Q6=i[2], o_Q7=i[1], o_Q8=i[0],
|
||||||
i_D=ts.i, i_CLK=ClockSignal("rtiox4"),
|
i_D=pad_i,
|
||||||
i_CE1=1, i_RST=ResetSignal(),
|
i_CLK=ClockSignal("rtiox4"),
|
||||||
|
i_CLKB=~ClockSignal("rtiox4"),
|
||||||
|
i_CE1=1, i_RST=0,
|
||||||
i_CLKDIV=ClockSignal("rio_phy"))
|
i_CLKDIV=ClockSignal("rio_phy"))
|
||||||
|
oserdes = _OSERDESE2_8X(pad_o)
|
||||||
oserdes = OSerdese2(ts.o)
|
|
||||||
self.submodules += oserdes
|
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 += [
|
self.comb += [
|
||||||
ts.oe.eq(~oserdes.t),
|
oserdes.t_in.eq(~self.oe),
|
||||||
oserdes.o.eq(o),
|
oserdes.o.eq(self.o)
|
||||||
oserdes.oe.eq(oe)
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Output(Module):
|
class Output_8X(ttl_serdes_generic.Output):
|
||||||
def __init__(self, pad):
|
def __init__(self, pad):
|
||||||
serdes = OSerdese2(pad)
|
serdes = _OSERDESE2_8X(pad)
|
||||||
self.submodules += ttl_serdes_generic.Output(serdes, fine_ts_width=3)
|
self.submodules += serdes
|
||||||
|
ttl_serdes_generic.Output.__init__(self, serdes)
|
||||||
|
|
||||||
|
|
||||||
class Inout(Module):
|
class Inout_8X(ttl_serdes_generic.Inout):
|
||||||
def __init__(self, pad):
|
def __init__(self, pad):
|
||||||
serdes = IOSerdese2(pad)
|
serdes = _IOSERDESE2_8X(pad)
|
||||||
self.submodules += ttl_serdes_generic.InOut(serdes, fine_ts_width=3)
|
self.submodules += serdes
|
||||||
|
ttl_serdes_generic.Inout.__init__(self, serdes)
|
||||||
|
|
|
@ -1,304 +1,273 @@
|
||||||
from migen.fhdl.std import *
|
from migen.fhdl.std import *
|
||||||
from artiq.gateware.rtio import rtlink
|
|
||||||
from migen.genlib.coding import PriorityEncoder
|
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):
|
class Output(Module):
|
||||||
def __init__(self, serdes, fine_ts_width=0):
|
def __init__(self, serdes):
|
||||||
self.rtlink = rtlink.Interface(rtlink.OInterface(1, fine_ts_width=
|
self.rtlink = rtlink.Interface(
|
||||||
fine_ts_width))
|
rtlink.OInterface(1, fine_ts_width=log2_int(flen(serdes.o))))
|
||||||
|
self.probes = [serdes.o[-1]]
|
||||||
serdes_width = 2**fine_ts_width
|
|
||||||
o = Signal()
|
|
||||||
previous_o = Signal()
|
|
||||||
override_en = Signal()
|
override_en = Signal()
|
||||||
override_o = Signal()
|
override_o = Signal()
|
||||||
io_o = Signal()
|
|
||||||
self.overrides = [override_en, override_o]
|
self.overrides = [override_en, override_o]
|
||||||
|
|
||||||
io = serdes
|
# # #
|
||||||
self.submodules += io
|
|
||||||
|
|
||||||
if fine_ts_width > 0:
|
self.submodules += _SerdesDriver(
|
||||||
timestamp = Signal(fine_ts_width)
|
serdes.o,
|
||||||
|
self.rtlink.o.stb, self.rtlink.o.data, self.rtlink.o.fine_ts,
|
||||||
# dout
|
override_en, override_o)
|
||||||
edges = Array([0xff ^ ((1 << i) - 1) for i in range(serdes_width)])
|
|
||||||
edge_out = Signal(serdes_width)
|
|
||||||
edge_out_n = Signal(serdes_width)
|
|
||||||
rise_out = Signal()
|
|
||||||
fall_out = Signal()
|
|
||||||
self.comb += [
|
|
||||||
timestamp.eq(self.rtlink.o.fine_ts),
|
|
||||||
edge_out.eq(edges[timestamp]),
|
|
||||||
edge_out_n.eq(~edge_out),
|
|
||||||
rise_out.eq(~previous_o & o),
|
|
||||||
fall_out.eq(previous_o & ~o),
|
|
||||||
If(override_en,
|
|
||||||
io.o.eq(override_o)
|
|
||||||
).Else(
|
|
||||||
If(rise_out,
|
|
||||||
io.o.eq(edge_out),
|
|
||||||
).Elif(fall_out,
|
|
||||||
io.o.eq(edge_out_n),
|
|
||||||
).Else(
|
|
||||||
io.o.eq(Replicate(o, serdes_width)),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
self.comb += [
|
|
||||||
If(override_en,
|
|
||||||
io_o.eq(override_o)
|
|
||||||
).Else(
|
|
||||||
io_o.eq(o)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
self.comb += [
|
|
||||||
io.o.eq(io_o),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.sync.rio_phy += [
|
|
||||||
If(self.rtlink.o.stb,
|
|
||||||
o.eq(self.rtlink.o.data),
|
|
||||||
),
|
|
||||||
previous_o.eq(o),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class Inout(Module):
|
class Inout(Module):
|
||||||
def __init__(self, serdes, fine_ts_width=0):
|
def __init__(self, serdes):
|
||||||
|
serdes_width = flen(serdes.o)
|
||||||
|
assert flen(serdes.i) == serdes_width
|
||||||
self.rtlink = rtlink.Interface(
|
self.rtlink = rtlink.Interface(
|
||||||
rtlink.OInterface(2, 2, fine_ts_width=fine_ts_width),
|
rtlink.OInterface(2, 2, fine_ts_width=log2_int(serdes_width)),
|
||||||
rtlink.IInterface(1, fine_ts_width=fine_ts_width))
|
rtlink.IInterface(1, fine_ts_width=log2_int(serdes_width)))
|
||||||
self.probes = []
|
self.probes = [serdes.i[-1], serdes.oe]
|
||||||
|
|
||||||
serdes_width = 2**fine_ts_width
|
|
||||||
self.io = io = serdes
|
|
||||||
self.submodules += io
|
|
||||||
io_o = Signal(serdes_width)
|
|
||||||
io_i = Signal(serdes_width)
|
|
||||||
o = Signal()
|
|
||||||
rising = Signal()
|
|
||||||
falling = Signal()
|
|
||||||
i0 = Signal()
|
|
||||||
self.oe = oe = Signal()
|
|
||||||
override_en = Signal()
|
override_en = Signal()
|
||||||
override_o = Signal()
|
override_o = Signal()
|
||||||
override_oe = Signal()
|
override_oe = Signal()
|
||||||
self.sensitivity = Signal(2)
|
|
||||||
self.overrides = [override_en, override_o, override_oe]
|
self.overrides = [override_en, override_o, override_oe]
|
||||||
previous_o = Signal()
|
|
||||||
|
|
||||||
if fine_ts_width > 0:
|
# # #
|
||||||
|
|
||||||
# Input
|
|
||||||
self.submodules.pe = pe = PriorityEncoder(serdes_width)
|
|
||||||
|
|
||||||
self.sync.rio_phy += i0.eq(io_i[-1])
|
|
||||||
|
|
||||||
self.comb += [
|
|
||||||
io_i.eq(io.i),
|
|
||||||
rising.eq(~i0 & io_i[-1]),
|
|
||||||
falling.eq(i0 & ~io_i[-1]),
|
|
||||||
pe.i.eq(io_i ^ Replicate(falling, serdes_width)),
|
|
||||||
self.rtlink.i.data.eq(io_i[-1]),
|
|
||||||
self.rtlink.i.fine_ts.eq(pe.o),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
timestamp = Signal(fine_ts_width)
|
self.submodules += _SerdesDriver(
|
||||||
edges = Array([0xff ^ ((1 << i) - 1) for i in range(serdes_width)])
|
serdes_o=serdes.o,
|
||||||
edge_out = Signal(serdes_width)
|
stb=self.rtlink.o.stb & (self.rtlink.o.address == 0),
|
||||||
edge_out_n = Signal(serdes_width)
|
data=self.rtlink.o.data[0],
|
||||||
rise_out = Signal()
|
fine_ts=self.rtlink.o.fine_ts,
|
||||||
fall_out = Signal()
|
override_en=override_en, override_o=override_o)
|
||||||
|
|
||||||
self.comb += [
|
|
||||||
timestamp.eq(self.rtlink.o.fine_ts),
|
|
||||||
edge_out.eq(edges[timestamp]),
|
|
||||||
edge_out_n.eq(~edge_out),
|
|
||||||
rise_out.eq(~previous_o & o),
|
|
||||||
fall_out.eq(previous_o & ~o),
|
|
||||||
If(override_en,
|
|
||||||
io_o.eq(override_o),
|
|
||||||
).Else(
|
|
||||||
If(rise_out,
|
|
||||||
io_o.eq(edge_out),
|
|
||||||
).Elif(fall_out,
|
|
||||||
io_o.eq(edge_out_n),
|
|
||||||
).Else(
|
|
||||||
io_o.eq(Replicate(o, serdes_width)),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
self.comb += [
|
|
||||||
io_i.eq(io.i),
|
|
||||||
rising.eq(~i0 & io_i),
|
|
||||||
falling.eq(i0 & ~io_i),
|
|
||||||
If(override_en,
|
|
||||||
io_o.eq(override_o)
|
|
||||||
).Else(
|
|
||||||
io_o.eq(o),
|
|
||||||
),
|
|
||||||
self.rtlink.i.data.eq(io_i),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.comb += [
|
|
||||||
io.oe.eq(oe),
|
|
||||||
io.o.eq(io_o),
|
|
||||||
self.rtlink.i.stb.eq(
|
|
||||||
(self.sensitivity[0] & rising) |
|
|
||||||
(self.sensitivity[1] & falling)
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
oe_k = Signal()
|
||||||
self.sync.rio_phy += [
|
self.sync.rio_phy += [
|
||||||
If(self.rtlink.o.stb,
|
If(self.rtlink.o.stb & (self.rtlink.o.address == 1),
|
||||||
If(self.rtlink.o.address == 0, o.eq(self.rtlink.o.data[0])),
|
oe_k.eq(self.rtlink.o.data[0])),
|
||||||
If(self.rtlink.o.address == 1, oe.eq(self.rtlink.o.data[0])),
|
|
||||||
),
|
|
||||||
If(override_en,
|
If(override_en,
|
||||||
oe.eq(override_oe)
|
serdes.oe.eq(override_oe)
|
||||||
),
|
).Else(
|
||||||
previous_o.eq(o),
|
serdes.oe.eq(oe_k)
|
||||||
]
|
|
||||||
|
|
||||||
self.sync.rio += [
|
|
||||||
If(self.rtlink.o.stb & (self.rtlink.o.address == 2),
|
|
||||||
self.sensitivity.eq(self.rtlink.o.data)
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
class FakeSerdes(Module):
|
# 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):
|
def __init__(self):
|
||||||
self.o = o = Signal(8)
|
self.o = Signal(8)
|
||||||
self.oe = oe = Signal(8)
|
self.i = Signal(8)
|
||||||
|
self.oe = Signal()
|
||||||
|
|
||||||
|
|
||||||
class FakeIOSerdes(Module):
|
class _OutputTB(Module):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.o = o = Signal(8)
|
serdes = _FakeSerdes()
|
||||||
self.oe = oe = Signal(8)
|
self.submodules.dut = RenameClockDomains(Output(serdes),
|
||||||
self.i = i = Signal(8)
|
|
||||||
|
|
||||||
|
|
||||||
class OutputTB(Module):
|
|
||||||
def __init__(self):
|
|
||||||
serdes = FakeSerdes()
|
|
||||||
self.o = RenameClockDomains(Output(serdes, fine_ts_width=3),
|
|
||||||
{"rio_phy": "sys"})
|
{"rio_phy": "sys"})
|
||||||
self.submodules += self.o
|
|
||||||
|
|
||||||
def gen_simulation(self, selfp):
|
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
|
yield
|
||||||
selfp.o.rtlink.o.data = 1
|
selfp.dut.rtlink.o.stb = 0
|
||||||
selfp.o.rtlink.o.fine_ts = 1
|
|
||||||
selfp.o.rtlink.o.stb = 1
|
|
||||||
yield
|
yield
|
||||||
selfp.o.rtlink.o.stb = 0
|
selfp.dut.rtlink.o.data = 0
|
||||||
|
selfp.dut.rtlink.o.fine_ts = 2
|
||||||
|
selfp.dut.rtlink.o.stb = 1
|
||||||
yield
|
yield
|
||||||
selfp.o.rtlink.o.data = 0
|
|
||||||
selfp.o.rtlink.o.fine_ts = 2
|
|
||||||
selfp.o.rtlink.o.stb = 1
|
|
||||||
yield
|
yield
|
||||||
selfp.o.rtlink.o.data = 1
|
selfp.dut.rtlink.o.data = 1
|
||||||
selfp.o.rtlink.o.fine_ts = 7
|
selfp.dut.rtlink.o.fine_ts = 7
|
||||||
yield
|
selfp.dut.rtlink.o.stb = 1
|
||||||
|
for _ in range(6):
|
||||||
while True:
|
# note that stb stays active; output should not change
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
class InoutTB(Module):
|
class _InoutTB(Module):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
ioserdes = FakeIOSerdes()
|
self.serdes = _FakeSerdes()
|
||||||
self.io = RenameClockDomains(Inout(ioserdes, fine_ts_width=3),
|
self.submodules.dut = RenameClockDomains(Inout(self.serdes),
|
||||||
{"rio_phy": "sys"})
|
{"rio_phy": "sys",
|
||||||
self.submodules += self.io
|
"rio": "sys"})
|
||||||
|
|
||||||
def check_input(self, selfp, stb, fine_ts=None):
|
def check_input(self, selfp, stb, fine_ts=None):
|
||||||
if stb != selfp.io.rtlink.i.stb:
|
if stb != selfp.dut.rtlink.i.stb:
|
||||||
print("KO rtlink.i.stb should be {} but is {}"
|
print("KO rtlink.i.stb should be {} but is {}"
|
||||||
.format(stb, selfp.io.rtlink.i.stb))
|
.format(stb, selfp.dut.rtlink.i.stb))
|
||||||
elif fine_ts is not None and fine_ts != selfp.io.rtlink.i.fine_ts:
|
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 {}"
|
print("KO rtlink.i.fine_ts should be {} but is {}"
|
||||||
.format(fine_ts, selfp.io.rtlink.i.fine_ts))
|
.format(fine_ts, selfp.dut.rtlink.i.fine_ts))
|
||||||
else:
|
else:
|
||||||
print("OK")
|
print("OK")
|
||||||
|
|
||||||
def check_output(self, selfp, data):
|
def check_output(self, selfp, data):
|
||||||
if selfp.io.io.o != data:
|
if selfp.serdes.o != data:
|
||||||
print("KO io.o should be {} but is {}".format(data, selfp.io.io.o))
|
print("KO io.o should be {} but is {}".format(data, selfp.serdes.o))
|
||||||
else:
|
else:
|
||||||
print("OK")
|
print("OK")
|
||||||
|
|
||||||
def check_output_enable(self, selfp, oe):
|
def check_output_enable(self, selfp, oe):
|
||||||
if selfp.io.io.oe != oe:
|
if selfp.serdes.oe != oe:
|
||||||
print("KO io.oe should be {} but is {}".format(oe, selfp.io.io.oe))
|
print("KO io.oe should be {} but is {}".format(oe, selfp.serdes.oe))
|
||||||
else:
|
else:
|
||||||
print("OK")
|
print("OK")
|
||||||
|
|
||||||
def gen_simulation(self, selfp):
|
def gen_simulation(self, selfp):
|
||||||
selfp.io.sensitivity = 0b11 # rising + falling
|
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)
|
self.check_output_enable(selfp, 0)
|
||||||
yield
|
yield
|
||||||
selfp.io.io.i = 0b11111110 # rising edge at fine_ts = 1
|
|
||||||
|
selfp.serdes.i = 0b11111110 # rising edge at fine_ts = 1
|
||||||
|
yield
|
||||||
|
selfp.serdes.i = 0b11111111
|
||||||
yield
|
yield
|
||||||
self.check_input(selfp, stb=1, fine_ts=1)
|
self.check_input(selfp, stb=1, fine_ts=1)
|
||||||
selfp.io.io.i = 0b01111111 # falling edge at fine_ts = 7
|
|
||||||
|
selfp.serdes.i = 0b01111111 # falling edge at fine_ts = 7
|
||||||
|
yield
|
||||||
|
selfp.serdes.i = 0b00000000
|
||||||
yield
|
yield
|
||||||
self.check_input(selfp, stb=1, fine_ts=7)
|
self.check_input(selfp, stb=1, fine_ts=7)
|
||||||
selfp.io.io.i = 0b11000000 # rising edge at fine_ts = 6
|
|
||||||
|
selfp.serdes.i = 0b11000000 # rising edge at fine_ts = 6
|
||||||
|
yield
|
||||||
|
selfp.serdes.i = 0b11111111
|
||||||
yield
|
yield
|
||||||
self.check_input(selfp, stb=1, fine_ts=6)
|
self.check_input(selfp, stb=1, fine_ts=6)
|
||||||
selfp.io.sensitivity = 0b01 # rising
|
|
||||||
selfp.io.io.i = 0b00001111 # falling edge at fine_ts = 4
|
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
|
yield
|
||||||
self.check_input(selfp, stb=0) # no strobe, sensitivity is rising edge
|
self.check_input(selfp, stb=0) # no strobe, sensitivity is rising edge
|
||||||
selfp.io.io.i = 0b11110000 # rising edge at fine_ts = 4
|
|
||||||
|
selfp.serdes.i = 0b11110000 # rising edge at fine_ts = 4
|
||||||
yield
|
yield
|
||||||
self.check_input(selfp, stb=1, fine_ts=4)
|
self.check_input(selfp, stb=1, fine_ts=4)
|
||||||
selfp.io.rtlink.o.address = 1
|
|
||||||
selfp.io.rtlink.o.data = 1
|
selfp.dut.rtlink.o.address = 1
|
||||||
selfp.io.rtlink.o.stb = 1 # set Output Enable to 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
|
||||||
selfp.io.rtlink.o.address = 0
|
|
||||||
selfp.io.rtlink.o.data = 1
|
|
||||||
selfp.io.rtlink.o.fine_ts = 3 # rising edge at fine_ts = 3
|
|
||||||
yield
|
yield
|
||||||
self.check_output_enable(selfp, 1)
|
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
|
yield
|
||||||
selfp.io.rtlink.o.data = 0
|
|
||||||
selfp.io.rtlink.o.fine_ts = 0 # falling edge at fine_ts = 0
|
|
||||||
self.check_output(selfp, data=0b11111000)
|
self.check_output(selfp, data=0b11111000)
|
||||||
|
|
||||||
yield
|
yield
|
||||||
self.check_output(selfp, data=0xFF) # stays at 1
|
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
|
yield
|
||||||
selfp.io.rtlink.o.data = 1
|
selfp.dut.rtlink.o.stb = 0
|
||||||
selfp.io.rtlink.o.fine_ts = 7
|
|
||||||
self.check_output(selfp, data=0)
|
|
||||||
yield
|
yield
|
||||||
self.check_output(selfp, data=0)
|
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
|
yield
|
||||||
self.check_output(selfp, data=0b10000000)
|
self.check_output(selfp, data=0b10000000)
|
||||||
while True:
|
|
||||||
yield
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
from migen.sim.generic import Simulator, TopLevel
|
from migen.sim.generic import Simulator, TopLevel
|
||||||
from migen.sim import icarus
|
|
||||||
|
|
||||||
if len(sys.argv) <= 1:
|
if len(sys.argv) != 2:
|
||||||
print("You should run this script with either InoutTB() or OutputTB() "
|
print("Incorrect command line")
|
||||||
"arg")
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
with Simulator(eval(sys.argv[1]), TopLevel("top.vcd", clk_period=int(1/0.125)),
|
cls = {
|
||||||
icarus.Runner(keep_files=False,)) as s:
|
"output": _OutputTB,
|
||||||
s.run(200)
|
"inout": _InoutTB
|
||||||
|
}[sys.argv[1]]
|
||||||
|
|
||||||
|
with Simulator(cls(), TopLevel("top.vcd", clk_period=int(1/0.125))) as s:
|
||||||
|
s.run()
|
||||||
|
|
Loading…
Reference in New Issue