forked from M-Labs/artiq
drtio: add rt_packets TX datapath, fixes
This commit is contained in:
parent
76bac21d14
commit
cb0d1549c6
@ -1,15 +1,24 @@
|
|||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
from migen import *
|
from migen import *
|
||||||
from migen.genlib.fsm import *
|
from migen.genlib.fsm import *
|
||||||
from migen.genlib.record import *
|
|
||||||
|
|
||||||
|
def layout_len(l):
|
||||||
|
return sum(e[1] for e in l)
|
||||||
|
|
||||||
|
|
||||||
class PacketLayoutManager:
|
class PacketLayoutManager:
|
||||||
def __init__(self, alignment):
|
def __init__(self, alignment):
|
||||||
self.alignment = alignment
|
self.alignment = alignment
|
||||||
self.layouts = dict()
|
self.layouts = dict()
|
||||||
self.types = dict()
|
self.types = dict()
|
||||||
|
self.type_names = dict()
|
||||||
|
|
||||||
def add_type(self, name, *fields, pad=True):
|
def add_type(self, name, *fields, pad=True):
|
||||||
self.types[name] = len(self.types)
|
type_n = len(self.types)
|
||||||
|
self.types[name] = type_n
|
||||||
|
self.type_names[type_n] = name
|
||||||
layout = [("ty", 8)] + list(fields)
|
layout = [("ty", 8)] + list(fields)
|
||||||
misalignment = layout_len(layout) % self.alignment
|
misalignment = layout_len(layout) % self.alignment
|
||||||
if misalignment:
|
if misalignment:
|
||||||
@ -32,11 +41,18 @@ def get_m2s_layouts(alignment):
|
|||||||
|
|
||||||
def get_s2m_layouts(alignment):
|
def get_s2m_layouts(alignment):
|
||||||
plm = PacketLayoutManager(alignment)
|
plm = PacketLayoutManager(alignment)
|
||||||
|
plm.add_type("error", ("code", 8))
|
||||||
plm.add_type("echo_reply")
|
plm.add_type("echo_reply")
|
||||||
plm.add_type("fifo_level_reply", ("level", 24))
|
plm.add_type("fifo_level_reply", ("level", 24))
|
||||||
return plm
|
return plm
|
||||||
|
|
||||||
|
|
||||||
|
error_codes = {
|
||||||
|
"frame_missed": 0,
|
||||||
|
"unknown_type": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ReceiveDatapath(Module):
|
class ReceiveDatapath(Module):
|
||||||
def __init__(self, ws, plm):
|
def __init__(self, ws, plm):
|
||||||
# inputs
|
# inputs
|
||||||
@ -56,8 +72,8 @@ class ReceiveDatapath(Module):
|
|||||||
# # #
|
# # #
|
||||||
|
|
||||||
# input pipeline stage - determine packet length based on type
|
# input pipeline stage - determine packet length based on type
|
||||||
lastword_per_type = [layout_len(l)//ws - 1
|
lastword_per_type = [layout_len(plm.layouts[plm.type_names[i]])//ws - 1
|
||||||
for l in plm.layouts.values()]
|
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(self.frame),
|
||||||
@ -84,10 +100,73 @@ class ReceiveDatapath(Module):
|
|||||||
)
|
)
|
||||||
self.comb += self.packet_last.eq(packet_buffer_count == packet_last_n)
|
self.comb += self.packet_last.eq(packet_buffer_count == packet_last_n)
|
||||||
|
|
||||||
# cast packet
|
# dissect packet
|
||||||
for name, layout in plm.layouts.items():
|
for name, layout in plm.layouts.items():
|
||||||
self.packet_as[name] = Record(layout)
|
fields = SimpleNamespace()
|
||||||
self.comb += self.packet_as[name].raw_bits().eq(packet_buffer)
|
idx = 0
|
||||||
|
for field_name, field_size in layout:
|
||||||
|
setattr(fields, field_name, packet_buffer[idx:idx+field_size])
|
||||||
|
idx += field_size
|
||||||
|
self.packet_as[name] = fields
|
||||||
|
|
||||||
|
|
||||||
|
class TransmitDatapath(Module):
|
||||||
|
def __init__(self, ws, plm):
|
||||||
|
self.ws = ws
|
||||||
|
self.plm = plm
|
||||||
|
|
||||||
|
# inputs
|
||||||
|
self.packet_buffer = Signal(max(layout_len(l)
|
||||||
|
for l in plm.layouts.values()))
|
||||||
|
w_in_packet = len(self.packet_buffer)//ws
|
||||||
|
self.packet_len = Signal(max=w_in_packet+1)
|
||||||
|
|
||||||
|
# control
|
||||||
|
self.stb = Signal()
|
||||||
|
self.done = Signal()
|
||||||
|
|
||||||
|
# outputs
|
||||||
|
self.frame = Signal()
|
||||||
|
self.data = Signal(ws)
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
packet_buffer_count = Signal(max=w_in_packet+1)
|
||||||
|
self.sync += [
|
||||||
|
self.done.eq(0),
|
||||||
|
self.frame.eq(0),
|
||||||
|
packet_buffer_count.eq(0),
|
||||||
|
|
||||||
|
If(self.stb & ~self.done,
|
||||||
|
If(packet_buffer_count == self.packet_len,
|
||||||
|
self.done.eq(1)
|
||||||
|
).Else(
|
||||||
|
self.frame.eq(1),
|
||||||
|
Case(packet_buffer_count,
|
||||||
|
{i: self.data.eq(self.packet_buffer[i*ws:(i+1)*ws])
|
||||||
|
for i in range(w_in_packet)}),
|
||||||
|
packet_buffer_count.eq(packet_buffer_count + 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
def send(self, ty, **kwargs):
|
||||||
|
idx = 8
|
||||||
|
value = self.plm.types[ty]
|
||||||
|
for field_name, field_size in self.plm.layouts[ty][1:]:
|
||||||
|
try:
|
||||||
|
fvalue = kwargs[field_name]
|
||||||
|
del kwargs[field_name]
|
||||||
|
except KeyError:
|
||||||
|
fvalue = 0
|
||||||
|
value = value | (fvalue << idx)
|
||||||
|
idx += field_size
|
||||||
|
if kwargs:
|
||||||
|
raise ValueError
|
||||||
|
return [
|
||||||
|
self.packet_buffer.eq(value),
|
||||||
|
self.packet_len.eq(idx//self.ws)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class RTPacketSatellite(Module):
|
class RTPacketSatellite(Module):
|
||||||
@ -109,7 +188,15 @@ class RTPacketSatellite(Module):
|
|||||||
rx_dp.data.eq(self.rx_rt_data)
|
rx_dp.data.eq(self.rx_rt_data)
|
||||||
]
|
]
|
||||||
|
|
||||||
fsm = FSM(reset_state="WAIT_FRAME")
|
tx_plm = get_s2m_layouts(ws)
|
||||||
|
tx_dp = TransmitDatapath(ws, tx_plm)
|
||||||
|
self.submodules += tx_dp
|
||||||
|
self.comb += [
|
||||||
|
self.tx_rt_frame.eq(tx_dp.frame),
|
||||||
|
self.tx_rt_data.eq(tx_dp.data)
|
||||||
|
]
|
||||||
|
|
||||||
|
fsm = FSM(reset_state="WAIT_INPUT")
|
||||||
self.submodules += fsm
|
self.submodules += fsm
|
||||||
|
|
||||||
continuation = Signal()
|
continuation = Signal()
|
||||||
@ -123,7 +210,7 @@ class RTPacketSatellite(Module):
|
|||||||
If(rx_dp.frame_r,
|
If(rx_dp.frame_r,
|
||||||
If(~frame_r_r | continuation_r,
|
If(~frame_r_r | continuation_r,
|
||||||
continuation.eq(1),
|
continuation.eq(1),
|
||||||
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, {
|
||||||
rx_plm.types["echo_request"]: NextState("ECHO"),
|
rx_plm.types["echo_request"]: NextState("ECHO"),
|
||||||
@ -135,12 +222,18 @@ class RTPacketSatellite(Module):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.state("ECHO",
|
fsm.act("ECHO",
|
||||||
NextState("WAIT_INPUT")
|
tx_dp.send("echo_reply"),
|
||||||
|
tx_dp.stb.eq(1),
|
||||||
|
If(tx_dp.done, NextState("WAIT_INPUT"))
|
||||||
)
|
)
|
||||||
fsm.state("ERROR_FRAME_MISSED",
|
fsm.act("ERROR_FRAME_MISSED",
|
||||||
NextState("WAIT_INPUT")
|
tx_dp.send("error", code=error_codes["frame_missed"]),
|
||||||
|
tx_dp.stb.eq(1),
|
||||||
|
If(tx_dp.done, NextState("WAIT_INPUT"))
|
||||||
)
|
)
|
||||||
fsm.state("ERROR_UNKNOWN_TYPE",
|
fsm.act("ERROR_UNKNOWN_TYPE",
|
||||||
NextState("WAIT_INPUT")
|
tx_dp.send("error", code=error_codes["unknown_type"]),
|
||||||
|
tx_dp.stb.eq(1),
|
||||||
|
If(tx_dp.done, NextState("WAIT_INPUT"))
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user