forked from M-Labs/artiq
drtio: structure
This commit is contained in:
parent
87ec333f55
commit
a40b39e9a2
|
@ -0,0 +1,2 @@
|
||||||
|
from artiq.gateware.drtio.core import DRTIOSatellite, DRTIOMaster
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
from migen import *
|
||||||
|
|
||||||
|
from artiq.gateware.drtio import link_layer, rt_packets, iot
|
||||||
|
|
||||||
|
|
||||||
|
class DRTIOSatellite(Module):
|
||||||
|
def __init__(self, transceiver, channels, full_ts_width=63, fine_ts_width=3):
|
||||||
|
self.submodules.link_layer = link_layer.LinkLayer(
|
||||||
|
transceiver.encoder, transceiver.decoders)
|
||||||
|
self.submodules.rt_packets = rt_packets.RTPacketSatellite(
|
||||||
|
self.link_layer)
|
||||||
|
self.submodules.iot = iot.IOT(
|
||||||
|
self.rt_packets, channels, full_ts_width, fine_ts_width)
|
||||||
|
|
||||||
|
|
||||||
|
class DRTIOMaster(Module):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
|
@ -0,0 +1,9 @@
|
||||||
|
from migen import *
|
||||||
|
from migen.genlib.fifo import SyncFIFOBuffered
|
||||||
|
|
||||||
|
from artiq.gateware.rtio import rtlink
|
||||||
|
|
||||||
|
|
||||||
|
class IOT(Module):
|
||||||
|
def __init__(self, rt_packets, channels, full_ts_width, fine_ts_width):
|
||||||
|
pass
|
|
@ -58,10 +58,8 @@ error_codes = {
|
||||||
|
|
||||||
|
|
||||||
class ReceiveDatapath(Module):
|
class ReceiveDatapath(Module):
|
||||||
def __init__(self, ws, plm):
|
def __init__(self, frame, data, plm):
|
||||||
# inputs
|
ws = len(data)
|
||||||
self.frame = Signal()
|
|
||||||
self.data = Signal(ws)
|
|
||||||
|
|
||||||
# control
|
# control
|
||||||
self.packet_buffer_load = Signal()
|
self.packet_buffer_load = Signal()
|
||||||
|
@ -80,11 +78,11 @@ class ReceiveDatapath(Module):
|
||||||
for i in range(len(plm.layouts))]
|
for i in range(len(plm.layouts))]
|
||||||
packet_last_n = Signal(max=max(lastword_per_type)+1)
|
packet_last_n = Signal(max=max(lastword_per_type)+1)
|
||||||
self.sync += [
|
self.sync += [
|
||||||
self.frame_r.eq(self.frame),
|
self.frame_r.eq(frame),
|
||||||
self.data_r.eq(self.data),
|
self.data_r.eq(data),
|
||||||
If(self.frame & ~self.frame_r,
|
If(frame & ~self.frame_r,
|
||||||
self.packet_type.eq(self.data[:8]),
|
self.packet_type.eq(data[:8]),
|
||||||
packet_last_n.eq(Array(lastword_per_type)[self.data[:8]])
|
packet_last_n.eq(Array(lastword_per_type)[data[:8]])
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -115,7 +113,9 @@ class ReceiveDatapath(Module):
|
||||||
|
|
||||||
|
|
||||||
class TransmitDatapath(Module):
|
class TransmitDatapath(Module):
|
||||||
def __init__(self, ws, plm):
|
def __init__(self, frame, data, plm):
|
||||||
|
ws = len(data)
|
||||||
|
assert ws % 8 == 0
|
||||||
self.ws = ws
|
self.ws = ws
|
||||||
self.plm = plm
|
self.plm = plm
|
||||||
|
|
||||||
|
@ -129,25 +129,21 @@ class TransmitDatapath(Module):
|
||||||
self.stb = Signal()
|
self.stb = Signal()
|
||||||
self.done = Signal()
|
self.done = Signal()
|
||||||
|
|
||||||
# outputs
|
|
||||||
self.frame = Signal()
|
|
||||||
self.data = Signal(ws)
|
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
packet_buffer_count = Signal(max=w_in_packet+1)
|
packet_buffer_count = Signal(max=w_in_packet+1)
|
||||||
self.sync += [
|
self.sync += [
|
||||||
self.done.eq(0),
|
self.done.eq(0),
|
||||||
self.frame.eq(0),
|
frame.eq(0),
|
||||||
packet_buffer_count.eq(0),
|
packet_buffer_count.eq(0),
|
||||||
|
|
||||||
If(self.stb & ~self.done,
|
If(self.stb & ~self.done,
|
||||||
If(packet_buffer_count == self.packet_len,
|
If(packet_buffer_count == self.packet_len,
|
||||||
self.done.eq(1)
|
self.done.eq(1)
|
||||||
).Else(
|
).Else(
|
||||||
self.frame.eq(1),
|
frame.eq(1),
|
||||||
Case(packet_buffer_count,
|
Case(packet_buffer_count,
|
||||||
{i: self.data.eq(self.packet_buffer[i*ws:(i+1)*ws])
|
{i: data.eq(self.packet_buffer[i*ws:(i+1)*ws])
|
||||||
for i in range(w_in_packet)}),
|
for i in range(w_in_packet)}),
|
||||||
packet_buffer_count.eq(packet_buffer_count + 1)
|
packet_buffer_count.eq(packet_buffer_count + 1)
|
||||||
)
|
)
|
||||||
|
@ -174,15 +170,7 @@ class TransmitDatapath(Module):
|
||||||
|
|
||||||
|
|
||||||
class RTPacketSatellite(Module):
|
class RTPacketSatellite(Module):
|
||||||
def __init__(self, nwords):
|
def __init__(self, link_layer):
|
||||||
# link layer interface
|
|
||||||
ws = 8*nwords
|
|
||||||
self.rx_rt_frame = Signal()
|
|
||||||
self.rx_rt_data = Signal(ws)
|
|
||||||
self.tx_rt_frame = Signal()
|
|
||||||
self.tx_rt_data = Signal(ws)
|
|
||||||
|
|
||||||
# I/O Timer interface
|
|
||||||
self.tsc_load = Signal()
|
self.tsc_load = Signal()
|
||||||
self.tsc_value = Signal(64)
|
self.tsc_value = Signal(64)
|
||||||
|
|
||||||
|
@ -200,24 +188,20 @@ class RTPacketSatellite(Module):
|
||||||
self.write_underflow = Signal()
|
self.write_underflow = Signal()
|
||||||
self.write_underflow_ack = Signal()
|
self.write_underflow_ack = Signal()
|
||||||
|
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
# RX/TX datapath
|
# RX/TX datapath
|
||||||
|
assert len(link_layer.tx_rt_data) == len(link_layer.rx_rt_data)
|
||||||
|
assert len(link_layer.tx_rt_data) % 8 == 0
|
||||||
|
ws = len(link_layer.tx_rt_data)
|
||||||
rx_plm = get_m2s_layouts(ws)
|
rx_plm = get_m2s_layouts(ws)
|
||||||
rx_dp = ReceiveDatapath(ws, rx_plm)
|
rx_dp = ReceiveDatapath(
|
||||||
|
link_layer.rx_rt_frame, link_layer.rx_rt_data, rx_plm)
|
||||||
self.submodules += rx_dp
|
self.submodules += rx_dp
|
||||||
self.comb += [
|
|
||||||
rx_dp.frame.eq(self.rx_rt_frame),
|
|
||||||
rx_dp.data.eq(self.rx_rt_data)
|
|
||||||
]
|
|
||||||
tx_plm = get_s2m_layouts(ws)
|
tx_plm = get_s2m_layouts(ws)
|
||||||
tx_dp = TransmitDatapath(ws, tx_plm)
|
tx_dp = TransmitDatapath(
|
||||||
|
link_layer.tx_rt_frame, link_layer.tx_rt_data, tx_plm)
|
||||||
self.submodules += tx_dp
|
self.submodules += tx_dp
|
||||||
self.comb += [
|
|
||||||
self.tx_rt_frame.eq(tx_dp.frame),
|
|
||||||
self.tx_rt_data.eq(tx_dp.data)
|
|
||||||
]
|
|
||||||
|
|
||||||
# RX->TX
|
# RX->TX
|
||||||
echo_req = Signal()
|
echo_req = Signal()
|
||||||
|
@ -259,10 +243,13 @@ class RTPacketSatellite(Module):
|
||||||
rx_dp.packet_buffer_load.eq(1),
|
rx_dp.packet_buffer_load.eq(1),
|
||||||
If(rx_dp.packet_last,
|
If(rx_dp.packet_last,
|
||||||
Case(rx_dp.packet_type, {
|
Case(rx_dp.packet_type, {
|
||||||
|
# echo must have fixed latency, so there is no memory
|
||||||
|
# mechanism
|
||||||
rx_plm.types["echo_request"]: echo_req.eq(1),
|
rx_plm.types["echo_request"]: echo_req.eq(1),
|
||||||
rx_plm.types["set_time"]: NextState("SET_TIME"),
|
rx_plm.types["set_time"]: NextState("SET_TIME"),
|
||||||
rx_plm.types["write"]: NextState("WRITE"),
|
rx_plm.types["write"]: NextState("WRITE"),
|
||||||
rx_plm.types["fifo_level_request"]: NextState("FIFO_LEVEL"),
|
rx_plm.types["fifo_level_request"]:
|
||||||
|
NextState("FIFO_LEVEL"),
|
||||||
"default": [
|
"default": [
|
||||||
err_set.eq(1),
|
err_set.eq(1),
|
||||||
NextValue(err_code, error_codes["unknown_type"])]
|
NextValue(err_code, error_codes["unknown_type"])]
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
from migen import *
|
from migen import *
|
||||||
|
|
||||||
|
@ -6,15 +7,15 @@ from artiq.gateware.drtio.rt_packets import *
|
||||||
|
|
||||||
|
|
||||||
class PacketInterface:
|
class PacketInterface:
|
||||||
def __init__(self, direction, frame, data):
|
def __init__(self, direction, ws):
|
||||||
if direction == "m2s":
|
if direction == "m2s":
|
||||||
self.plm = get_m2s_layouts(len(data))
|
self.plm = get_m2s_layouts(ws)
|
||||||
elif direction == "s2m":
|
elif direction == "s2m":
|
||||||
self.plm = get_s2m_layouts(len(data))
|
self.plm = get_s2m_layouts(ws)
|
||||||
else:
|
else:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
self.frame = frame
|
self.frame = Signal()
|
||||||
self.data = data
|
self.data = Signal(ws)
|
||||||
|
|
||||||
def send(self, ty, **kwargs):
|
def send(self, ty, **kwargs):
|
||||||
idx = 8
|
idx = 8
|
||||||
|
@ -75,11 +76,17 @@ class PacketInterface:
|
||||||
|
|
||||||
|
|
||||||
class TestSatellite(unittest.TestCase):
|
class TestSatellite(unittest.TestCase):
|
||||||
|
def create_dut(self, nwords):
|
||||||
|
pt = PacketInterface("m2s", nwords*8)
|
||||||
|
pr = PacketInterface("s2m", nwords*8)
|
||||||
|
dut = RTPacketSatellite(SimpleNamespace(
|
||||||
|
rx_rt_frame=pt.frame, rx_rt_data=pt.data,
|
||||||
|
tx_rt_frame=pr.frame, tx_rt_data=pr.data))
|
||||||
|
return pt, pr, dut
|
||||||
|
|
||||||
def test_echo(self):
|
def test_echo(self):
|
||||||
for nwords in range(1, 8):
|
for nwords in range(1, 8):
|
||||||
dut = RTPacketSatellite(nwords)
|
pt, pr, dut = self.create_dut(nwords)
|
||||||
pt = PacketInterface("m2s", dut.rx_rt_frame, dut.rx_rt_data)
|
|
||||||
pr = PacketInterface("s2m", dut.tx_rt_frame, dut.tx_rt_data)
|
|
||||||
completed = False
|
completed = False
|
||||||
def send():
|
def send():
|
||||||
yield from pt.send("echo_request")
|
yield from pt.send("echo_request")
|
||||||
|
@ -94,8 +101,7 @@ class TestSatellite(unittest.TestCase):
|
||||||
|
|
||||||
def test_set_time(self):
|
def test_set_time(self):
|
||||||
for nwords in range(1, 8):
|
for nwords in range(1, 8):
|
||||||
dut = RTPacketSatellite(nwords)
|
pt, _, dut = self.create_dut(nwords)
|
||||||
pt = PacketInterface("m2s", dut.rx_rt_frame, dut.rx_rt_data)
|
|
||||||
tx_times = [0x12345678aabbccdd, 0x0102030405060708,
|
tx_times = [0x12345678aabbccdd, 0x0102030405060708,
|
||||||
0xaabbccddeeff1122]
|
0xaabbccddeeff1122]
|
||||||
def send():
|
def send():
|
||||||
|
@ -111,5 +117,5 @@ class TestSatellite(unittest.TestCase):
|
||||||
if (yield dut.tsc_load):
|
if (yield dut.tsc_load):
|
||||||
rx_times.append((yield dut.tsc_value))
|
rx_times.append((yield dut.tsc_value))
|
||||||
yield
|
yield
|
||||||
run_simulation(dut, [send(), receive()], vcd_name="foo.vcd")
|
run_simulation(dut, [send(), receive()])
|
||||||
self.assertEqual(tx_times, rx_times)
|
self.assertEqual(tx_times, rx_times)
|
||||||
|
|
Loading…
Reference in New Issue