From: Florent Kermarrec Date: Mon, 30 Sep 2019 21:31:34 +0000 (+0200) Subject: soc/interconnect: rename stream_packet to packet & cleanup (with retro-compat) X-Git-Tag: 24jan2021_ls180~952 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=427d7af76743169de5ba4c8430667b718ac95922;p=litex.git soc/interconnect: rename stream_packet to packet & cleanup (with retro-compat) --- diff --git a/litex/__init__.py b/litex/__init__.py index e1534fda..ca1e6d75 100644 --- a/litex/__init__.py +++ b/litex/__init__.py @@ -1,6 +1,11 @@ import sys -from litex.tools.litex_client import RemoteClient + +# retro-compat 2019-09-30 +from litex.soc.interconnect import packet +sys.modules["litex.soc.interconnect.stream_packet"] = packet # retro-compat 2019-09-29 from litex.soc.integration import export -sys.modules["litex.soc.integration.cpu_interface"] = export \ No newline at end of file +sys.modules["litex.soc.integration.cpu_interface"] = export + +from litex.tools.litex_client import RemoteClient diff --git a/litex/soc/interconnect/packet.py b/litex/soc/interconnect/packet.py new file mode 100644 index 00000000..d1d02fe1 --- /dev/null +++ b/litex/soc/interconnect/packet.py @@ -0,0 +1,329 @@ +# This file is Copyright (c) 2015-2019 Florent Kermarrec +# License: BSD + +from migen import * +from migen.genlib.roundrobin import * +from migen.genlib.record import * +from migen.genlib.fsm import FSM, NextState + +from litex.gen import * + +from litex.soc.interconnect import stream + +# Status ------------------------------------------------------------------------------------------- + +class Status(Module): + def __init__(self, endpoint): + self.first = Signal(reset=1) + self.last = Signal() + self.ongoing = Signal() + + ongoing = Signal() + self.comb += \ + If(endpoint.valid, + self.last.eq(endpoint.last & endpoint.ready) + ) + self.sync += ongoing.eq((endpoint.valid | ongoing) & ~self.last) + self.comb += self.ongoing.eq((endpoint.valid | ongoing) & ~self.last) + + self.sync += [ + If(self.last, + self.first.eq(1) + ).Elif(endpoint.valid & endpoint.ready, + self.first.eq(0) + ) + ] + +# Arbiter ------------------------------------------------------------------------------------------ + +class Arbiter(Module): + def __init__(self, masters, slave): + if len(masters) == 0: + pass + elif len(masters) == 1: + self.grant = Signal() + self.comb += masters.pop().connect(slave) + else: + self.submodules.rr = RoundRobin(len(masters)) + self.grant = self.rr.grant + cases = {} + for i, master in enumerate(masters): + status = Status(master) + self.submodules += status + self.comb += self.rr.request[i].eq(status.ongoing) + cases[i] = [master.connect(slave)] + self.comb += Case(self.grant, cases) + +# Dispatcher --------------------------------------------------------------------------------------- + +class Dispatcher(Module): + def __init__(self, master, slaves, one_hot=False): + if len(slaves) == 0: + self.sel = Signal() + elif len(slaves) == 1: + self.comb += master.connect(slaves.pop()) + self.sel = Signal() + else: + if one_hot: + self.sel = Signal(len(slaves)) + else: + self.sel = Signal(max=len(slaves)) + + # # # + + status = Status(master) + self.submodules += status + + sel = Signal.like(self.sel) + sel_ongoing = Signal.like(self.sel) + self.sync += \ + If(status.first, + sel_ongoing.eq(self.sel) + ) + self.comb += \ + If(status.first, + sel.eq(self.sel) + ).Else( + sel.eq(sel_ongoing) + ) + cases = {} + for i, slave in enumerate(slaves): + if one_hot: + idx = 2**i + else: + idx = i + cases[idx] = [master.connect(slave)] + cases["default"] = [master.ready.eq(1)] + self.comb += Case(sel, cases) + +# Header ------------------------------------------------------------------------------------------- + +class HeaderField: + def __init__(self, byte, offset, width): + self.byte = byte + self.offset = offset + self.width = width + + +class Header: + def __init__(self, fields, length, swap_field_bytes=True): + self.fields = fields + self.length = length + self.swap_field_bytes = swap_field_bytes + + def get_layout(self): + layout = [] + for k, v in sorted(self.fields.items()): + layout.append((k, v.width)) + return layout + + def get_field(self, obj, name, width): + if "_lsb" in name: + field = getattr(obj, name.replace("_lsb", ""))[:width] + elif "_msb" in name: + field = getattr(obj, name.replace("_msb", ""))[width:2*width] + else: + field = getattr(obj, name) + if len(field) != width: + raise ValueError("Width mismatch on " + name + " field") + return field + + def encode(self, obj, signal): + r = [] + for k, v in sorted(self.fields.items()): + start = v.byte*8 + v.offset + end = start + v.width + field = self.get_field(obj, k, v.width) + if self.swap_field_bytes: + field = reverse_bytes(field) + r.append(signal[start:end].eq(field)) + return r + + def decode(self, signal, obj): + r = [] + for k, v in sorted(self.fields.items()): + start = v.byte*8 + v.offset + end = start + v.width + field = self.get_field(obj, k, v.width) + if self.swap_field_bytes: + r.append(field.eq(reverse_bytes(signal[start:end]))) + else: + r.append(field.eq(signal[start:end])) + return r + +# Packetizer --------------------------------------------------------------------------------------- + +class Packetizer(Module): + def __init__(self, sink_description, source_description, header): + self.sink = sink = stream.Endpoint(sink_description) + self.source = source = stream.Endpoint(source_description) + self.header = Signal(header.length*8) + + # # # + + dw = len(self.sink.data) + + header_reg = Signal(header.length*8, reset_less=True) + header_words = (header.length*8)//dw + load = Signal() + shift = Signal() + counter = Signal(max=max(header_words, 2)) + counter_reset = Signal() + counter_ce = Signal() + self.sync += \ + If(counter_reset, + counter.eq(0) + ).Elif(counter_ce, + counter.eq(counter + 1) + ) + + self.comb += header.encode(sink, self.header) + if header_words == 1: + self.sync += [ + If(load, + header_reg.eq(self.header) + ) + ] + else: + self.sync += [ + If(load, + header_reg.eq(self.header) + ).Elif(shift, + header_reg.eq(Cat(header_reg[dw:], Signal(dw))) + ) + ] + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + + if header_words == 1: + idle_next_state = "COPY" + else: + idle_next_state = "SEND-HEADER" + + fsm.act("IDLE", + sink.ready.eq(1), + counter_reset.eq(1), + If(sink.valid, + sink.ready.eq(0), + source.valid.eq(1), + source.last.eq(0), + source.data.eq(self.header[:dw]), + If(source.valid & source.ready, + load.eq(1), + NextState(idle_next_state) + ) + ) + ) + if header_words != 1: + fsm.act("SEND-HEADER", + source.valid.eq(1), + source.last.eq(0), + source.data.eq(header_reg[dw:2*dw]), + If(source.valid & source.ready, + shift.eq(1), + counter_ce.eq(1), + If(counter == header_words-2, + NextState("COPY") + ) + ) + ) + if hasattr(sink, "error"): + self.comb += source.error.eq(sink.error) + fsm.act("COPY", + source.valid.eq(sink.valid), + source.last.eq(sink.last), + source.data.eq(sink.data), + If(source.valid & source.ready, + sink.ready.eq(1), + If(source.last, + NextState("IDLE") + ) + ) + ) + +# Depacketizer ------------------------------------------------------------------------------------- + +class Depacketizer(Module): + def __init__(self, sink_description, source_description, header): + self.sink = sink = stream.Endpoint(sink_description) + self.source = source = stream.Endpoint(source_description) + self.header = Signal(header.length*8) + + # # # + + dw = len(sink.data) + + header_reg = Signal(header.length*8, reset_less=True) + header_words = (header.length*8)//dw + + shift = Signal() + counter = Signal(max=max(header_words, 2)) + counter_reset = Signal() + counter_ce = Signal() + self.sync += \ + If(counter_reset, + counter.eq(0) + ).Elif(counter_ce, + counter.eq(counter + 1) + ) + + if header_words == 1: + self.sync += \ + If(shift, + header_reg.eq(sink.data) + ) + else: + self.sync += \ + If(shift, + header_reg.eq(Cat(header_reg[dw:], sink.data)) + ) + self.comb += self.header.eq(header_reg) + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + + if header_words == 1: + idle_next_state = "COPY" + else: + idle_next_state = "RECEIVE_HEADER" + + fsm.act("IDLE", + sink.ready.eq(1), + counter_reset.eq(1), + If(sink.valid, + shift.eq(1), + NextState(idle_next_state) + ) + ) + if header_words != 1: + fsm.act("RECEIVE_HEADER", + sink.ready.eq(1), + If(sink.valid, + counter_ce.eq(1), + shift.eq(1), + If(counter == header_words-2, + NextState("COPY") + ) + ) + ) + no_payload = Signal() + self.sync += \ + If(fsm.before_entering("COPY"), + no_payload.eq(sink.last) + ) + + if hasattr(sink, "error"): + self.comb += source.error.eq(sink.error) + self.comb += [ + source.last.eq(sink.last | no_payload), + source.data.eq(sink.data), + header.decode(self.header, source) + ] + fsm.act("COPY", + sink.ready.eq(source.ready), + source.valid.eq(sink.valid | no_payload), + If(source.valid & source.ready & source.last, + NextState("IDLE") + ) + ) diff --git a/litex/soc/interconnect/stream_packet.py b/litex/soc/interconnect/stream_packet.py deleted file mode 100644 index b9fd28a6..00000000 --- a/litex/soc/interconnect/stream_packet.py +++ /dev/null @@ -1,327 +0,0 @@ -# This file is Copyright (c) 2015-2018 Florent Kermarrec -# License: BSD - -from migen import * -from migen.genlib.roundrobin import * -from migen.genlib.record import * -from migen.genlib.fsm import FSM, NextState - -from litex.gen import * - -from litex.soc.interconnect import stream - -# TODO: clean up code below -# XXX - -class Status(Module): - def __init__(self, endpoint): - self.first = first = Signal(reset=1) - self.last = last = Signal() - self.ongoing = Signal() - - ongoing = Signal() - self.comb += \ - If(endpoint.valid, - last.eq(endpoint.last & endpoint.ready) - ) - self.sync += ongoing.eq((endpoint.valid | ongoing) & ~last) - self.comb += self.ongoing.eq((endpoint.valid | ongoing) & ~last) - - self.sync += [ - If(last, - first.eq(1) - ).Elif(endpoint.valid & endpoint.ready, - first.eq(0) - ) - ] - - -class Arbiter(Module): - def __init__(self, masters, slave): - if len(masters) == 0: - pass - elif len(masters) == 1: - self.grant = Signal() - self.comb += masters.pop().connect(slave) - else: - self.submodules.rr = RoundRobin(len(masters)) - self.grant = self.rr.grant - cases = {} - for i, master in enumerate(masters): - status = Status(master) - self.submodules += status - self.comb += self.rr.request[i].eq(status.ongoing) - cases[i] = [master.connect(slave)] - self.comb += Case(self.grant, cases) - - -class Dispatcher(Module): - def __init__(self, master, slaves, one_hot=False): - if len(slaves) == 0: - self.sel = Signal() - elif len(slaves) == 1: - self.comb += master.connect(slaves.pop()) - self.sel = Signal() - else: - if one_hot: - self.sel = Signal(len(slaves)) - else: - self.sel = Signal(max=len(slaves)) - - # # # - - status = Status(master) - self.submodules += status - - sel = Signal.like(self.sel) - sel_ongoing = Signal.like(self.sel) - self.sync += \ - If(status.first, - sel_ongoing.eq(self.sel) - ) - self.comb += \ - If(status.first, - sel.eq(self.sel) - ).Else( - sel.eq(sel_ongoing) - ) - cases = {} - for i, slave in enumerate(slaves): - if one_hot: - idx = 2**i - else: - idx = i - cases[idx] = [master.connect(slave)] - cases["default"] = [master.ready.eq(1)] - self.comb += Case(sel, cases) - - -class HeaderField: - def __init__(self, byte, offset, width): - self.byte = byte - self.offset = offset - self.width = width - - -class Header: - def __init__(self, fields, length, swap_field_bytes=True): - self.fields = fields - self.length = length - self.swap_field_bytes = swap_field_bytes - - def get_layout(self): - layout = [] - for k, v in sorted(self.fields.items()): - layout.append((k, v.width)) - return layout - - def get_field(self, obj, name, width): - if "_lsb" in name: - field = getattr(obj, name.replace("_lsb", ""))[:width] - elif "_msb" in name: - field = getattr(obj, name.replace("_msb", ""))[width:2*width] - else: - field = getattr(obj, name) - if len(field) != width: - raise ValueError("Width mismatch on " + name + " field") - return field - - def encode(self, obj, signal): - r = [] - for k, v in sorted(self.fields.items()): - start = v.byte*8 + v.offset - end = start + v.width - field = self.get_field(obj, k, v.width) - if self.swap_field_bytes: - field = reverse_bytes(field) - r.append(signal[start:end].eq(field)) - return r - - def decode(self, signal, obj): - r = [] - for k, v in sorted(self.fields.items()): - start = v.byte*8 + v.offset - end = start + v.width - field = self.get_field(obj, k, v.width) - if self.swap_field_bytes: - r.append(field.eq(reverse_bytes(signal[start:end]))) - else: - r.append(field.eq(signal[start:end])) - return r - - -class Packetizer(Module): - def __init__(self, sink_description, source_description, header): - self.sink = sink = stream.Endpoint(sink_description) - self.source = source = stream.Endpoint(source_description) - self.header = Signal(header.length*8) - - # # # - - dw = len(self.sink.data) - - header_reg = Signal(header.length*8, reset_less=True) - header_words = (header.length*8)//dw - load = Signal() - shift = Signal() - counter = Signal(max=max(header_words, 2)) - counter_reset = Signal() - counter_ce = Signal() - self.sync += \ - If(counter_reset, - counter.eq(0) - ).Elif(counter_ce, - counter.eq(counter + 1) - ) - - self.comb += header.encode(sink, self.header) - if header_words == 1: - self.sync += [ - If(load, - header_reg.eq(self.header) - ) - ] - else: - self.sync += [ - If(load, - header_reg.eq(self.header) - ).Elif(shift, - header_reg.eq(Cat(header_reg[dw:], Signal(dw))) - ) - ] - - fsm = FSM(reset_state="IDLE") - self.submodules += fsm - - if header_words == 1: - idle_next_state = "COPY" - else: - idle_next_state = "SEND_HEADER" - - fsm.act("IDLE", - sink.ready.eq(1), - counter_reset.eq(1), - If(sink.valid, - sink.ready.eq(0), - source.valid.eq(1), - source.last.eq(0), - source.data.eq(self.header[:dw]), - If(source.valid & source.ready, - load.eq(1), - NextState(idle_next_state) - ) - ) - ) - if header_words != 1: - fsm.act("SEND_HEADER", - source.valid.eq(1), - source.last.eq(0), - source.data.eq(header_reg[dw:2*dw]), - If(source.valid & source.ready, - shift.eq(1), - counter_ce.eq(1), - If(counter == header_words-2, - NextState("COPY") - ) - ) - ) - if hasattr(sink, "error"): - self.comb += source.error.eq(sink.error) - fsm.act("COPY", - source.valid.eq(sink.valid), - source.last.eq(sink.last), - source.data.eq(sink.data), - If(source.valid & source.ready, - sink.ready.eq(1), - If(source.last, - NextState("IDLE") - ) - ) - ) - - -class Depacketizer(Module): - def __init__(self, sink_description, source_description, header): - self.sink = sink = stream.Endpoint(sink_description) - self.source = source = stream.Endpoint(source_description) - self.header = Signal(header.length*8) - - # # # - - dw = len(sink.data) - - header_reg = Signal(header.length*8, reset_less=True) - header_words = (header.length*8)//dw - - shift = Signal() - counter = Signal(max=max(header_words, 2)) - counter_reset = Signal() - counter_ce = Signal() - self.sync += \ - If(counter_reset, - counter.eq(0) - ).Elif(counter_ce, - counter.eq(counter + 1) - ) - - if header_words == 1: - self.sync += \ - If(shift, - header_reg.eq(sink.data) - ) - else: - self.sync += \ - If(shift, - header_reg.eq(Cat(header_reg[dw:], sink.data)) - ) - self.comb += self.header.eq(header_reg) - - fsm = FSM(reset_state="IDLE") - self.submodules += fsm - - if header_words == 1: - idle_next_state = "COPY" - else: - idle_next_state = "RECEIVE_HEADER" - - fsm.act("IDLE", - sink.ready.eq(1), - counter_reset.eq(1), - If(sink.valid, - shift.eq(1), - NextState(idle_next_state) - ) - ) - if header_words != 1: - fsm.act("RECEIVE_HEADER", - sink.ready.eq(1), - If(sink.valid, - counter_ce.eq(1), - shift.eq(1), - If(counter == header_words-2, - NextState("COPY") - ) - ) - ) - no_payload = Signal() - self.sync += \ - If(fsm.before_entering("COPY"), - no_payload.eq(sink.last) - ) - - if hasattr(sink, "error"): - self.comb += source.error.eq(sink.error) - self.comb += [ - source.last.eq(sink.last | no_payload), - source.data.eq(sink.data), - header.decode(self.header, source) - ] - fsm.act("COPY", - sink.ready.eq(source.ready), - source.valid.eq(sink.valid | no_payload), - If(source.valid & source.ready & source.last, - NextState("IDLE") - ) - ) - -# XXX