Skip to content

Commit

Permalink
intersonnect/stream: simplify Converter (now only works on raw bits) …
Browse files Browse the repository at this point in the history
…and add StrideConverter to handle first-level user fields
enjoy-digital committed Mar 12, 2016
1 parent 9f74894 commit df3a45b
Showing 2 changed files with 93 additions and 62 deletions.
4 changes: 2 additions & 2 deletions misoc/cores/liteeth_mini/mac/core.py
Original file line number Diff line number Diff line change
@@ -66,10 +66,10 @@ def __init__(self, phy, dw, endianness="big",
# Converters
if dw != phy.dw:
reverse = endianness == "big"
tx_converter = stream.Converter(eth_phy_layout(dw),
tx_converter = stream.StrideConverter(eth_phy_layout(dw),
eth_phy_layout(phy.dw),
reverse=reverse)
rx_converter = stream.Converter(eth_phy_layout(phy.dw),
rx_converter = stream.StrideConverter(eth_phy_layout(phy.dw),
eth_phy_layout(dw),
reverse=reverse)
self.submodules += ClockDomainsRenamer("eth_tx")(tx_converter)
151 changes: 91 additions & 60 deletions misoc/interconnect/stream.py
Original file line number Diff line number Diff line change
@@ -165,15 +165,16 @@ def __init__(self, layout_from, layout_to, ratio, reverse):
]

# data path
source_payload_raw_bits = Signal(len(source.payload.raw_bits()))
cases = {}
for i in range(ratio):
n = ratio-i-1 if reverse else i
cases[i] = []
for name, width in layout_from:
src = getattr(self.sink, name)
dst = getattr(self.source, name)[n*width:(n+1)*width]
cases[i].append(dst.eq(src))
self.sync += If(load_part, Case(demux, cases))
width = len(sink.payload.raw_bits())
src = sink.payload.raw_bits()
dst = source_payload_raw_bits[n*width:(n+1)*width]
cases[i] = dst.eq(src)
self.sync += If(load_part, Case(demux, cases))
self.comb += source.payload.raw_bits().eq(source_payload_raw_bits)


class _DownConverter(Module):
@@ -202,79 +203,109 @@ def __init__(self, layout_from, layout_to, ratio, reverse):
)

# data path
sink_payload_raw_bits = Signal(len(sink.payload.raw_bits()))
self.comb += sink_payload_raw_bits.eq(sink.payload.raw_bits())
cases = {}
for i in range(ratio):
n = ratio-i-1 if reverse else i
cases[i] = []
for name, width in layout_to:
src = getattr(self.sink, name)[n*width:(n+1)*width]
dst = getattr(self.source, name)
cases[i].append(dst.eq(src))
self.comb += Case(mux, cases).makedefault()
width = len(source.payload.raw_bits())
src = sink_payload_raw_bits[n*width:(n+1)*width]
dst = source.payload.raw_bits()
cases[i] = dst.eq(src)
self.comb += Case(mux, cases).makedefault(),


class _IdentityConverter(Module):
def __init__(self, layout_from, layout_to, ratio, reverse):
self.sink = Endpoint(layout_from)
self.source = Endpoint(layout_to)
self.sink = sink = Endpoint(layout_from)
self.source = source = Endpoint(layout_to)

# # #

self.comb += self.sink.connect(self.source)
self.comb += sink.connect(source)


def _get_converter_ratio(layout_from, layout_to):
if len(layout_from) != len(layout_to):
raise ValueError("Incompatible layouts (number of elements)")

converter = None
ratio = None
for f_from, f_to in zip(layout_from, layout_to):
name_from, width_from = f_from
name_to, width_to = f_to

# check layouts
if not isinstance(width_to, int) or not isinstance(width_to, int):
raise ValueError("Sublayouts are not supported")
if name_from != name_to:
raise ValueError("Incompatible layouts (field names)")

# get current converter/ratio
if width_from > width_to:
current_converter = _DownConverter
if width_from % width_to:
raise ValueError("Ratio must be an int")
current_ratio = width_from//width_to
elif width_from < width_to:
current_converter = _UpConverter
if width_to % width_from:
raise ValueError("Ratio must be an int")
current_ratio = width_to//width_from
else:
current_converter = _IdentityConverter
current_ratio = 1
width_from = len(Endpoint(layout_from).payload.raw_bits())
width_to = len(Endpoint(layout_to).payload.raw_bits())

if width_from > width_to:
converter_cls = _DownConverter
if width_from % width_to:
raise ValueError("Ratio must be an int")
ratio = width_from//width_to
elif width_from < width_to:
converter_cls = _UpConverter
if width_to % width_from:
raise ValueError("Ratio must be an int")
ratio = width_to//width_from
else:
converter_cls = _IdentityConverter
ratio = 1

return converter_cls, ratio

# check converter
if converter is None:
converter = current_converter
if current_converter != converter:
raise ValueError("Incoherent layout fields (converter type)")

# check ratio
if ratio is None:
ratio = current_ratio
if current_ratio != ratio:
raise ValueError("Incoherent layout fields (ratio)")
class Converter(Module):
def __init__(self, layout_from, layout_to, reverse=False):
self.cls, self.ratio = _get_converter_ratio(layout_from, layout_to)

return converter, ratio
# # #

converter = self.cls(layout_from, layout_to, self.ratio, reverse)
self.submodules += converter

class Converter(Module):
self.sink, self.source = converter.sink, converter.source


class StrideConverter(Module):
def __init__(self, layout_from, layout_to, reverse=False):
converter, ratio = _get_converter_ratio(layout_from, layout_to)
self.sink = sink = Endpoint(layout_from)
self.source = source = Endpoint(layout_to)

# # #

self.submodules.converter = converter(layout_from, layout_to,
ratio, reverse)
self.sink, self.source = self.converter.sink, self.converter.source
width_from = len(sink.payload.raw_bits())
width_to = len(source.payload.raw_bits())

converter = Converter([("data", width_from)],
[("data", width_to)],
reverse)
self.submodules += converter

# cast sink to converter.sink (user fields --> raw bits)
self.comb += [
converter.sink.stb.eq(sink.stb),
converter.sink.eop.eq(sink.eop),
sink.ack.eq(converter.sink.ack)
]
if converter.cls == _DownConverter:
ratio = converter.ratio
for i in range(ratio):
j = 0
for name, width in layout_to:
src = getattr(sink, name)[i*width:(i+1)*width]
dst = converter.sink.data[i*width_to+j:i*width_to+j+width]
self.comb += dst.eq(src)
j += width
else:
self.comb += converter.sink.data.eq(sink.payload.raw_bits())


# cast converter.source to source (raw bits --> user fields)
self.comb += [
source.stb.eq(converter.source.stb),
source.eop.eq(converter.source.eop),
converter.source.ack.eq(source.ack)
]
if converter.cls == _UpConverter:
ratio = converter.ratio
for i in range(ratio):
j = 0
for name, width in layout_from:
src = converter.source.data[i*width_from+j:i*width_from+j+width]
dst = getattr(source, name)[i*width:(i+1)*width]
self.comb += dst.eq(src)
j += width
else:
self.comb += source.payload.raw_bits().eq(converter.source.data)

3 comments on commit df3a45b

@sbourdeauducq
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant is that the Converter should only be able to operate on layouts that are of the form [("data", nbits)]. It could create its endpoints itself, and take only the bit sizes (integers) as parameter.

@sbourdeauducq
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way you do not have to call raw_bits anywhere in the converter, and the addition of the chunks fields is easier.

@enjoy-digital
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok that's fine. I just did the changes and will test/commit it tomorrow.

Please sign in to comment.