[Libre-soc-bugs] [Bug 713] PartitionedSignal enhancement to add partition-context-aware lengths

bugzilla-daemon at libre-soc.org bugzilla-daemon at libre-soc.org
Thu Oct 7 05:56:36 BST 2021


--- Comment #22 from Luke Kenneth Casson Leighton <lkcl at lkcl.net> ---
(In reply to Jacob Lifshay from comment #20)

a quick readthrough:

> def layout(elwid, part_counts, lane_shapes):

using the FP example dict from comment #2, i think you might have
the idea is not to create a set of *separate* PartitionPoints
one per elwidth, the idea is to create a *merged* set of PartitionPoints
(and associated Signal mask)

normally PartitionPoints has to take a mask as input,
thus, we need a function that calculates the length of
that mask (see make_partition2 as an example)

>     if not isinstance(lane_shapes, Mapping):
>         lane_shapes = {i: lane_shapes for i in part_counts}
>     lane_shapes = {i: Shape.cast(lane_shapes[i]) for i in part_counts}
>     signed = lane_shapes[0].signed
>     assert all(i.signed == signed for i in lane_shapes.values())

by removing signed all of these lines can go.  this reduces the function
by 25%.   lane_shapes can become a straight dict containing
numbers, Shape can dral with the signed argument.

>     part_wid = -min(-lane_shapes[i].width // c for i, c in
> part_counts.items())
>     part_count = max(part_counts.values())

unfortunately this lwts the function determine the lwngth
of the underlying Signal, which is where i think you are getting
the mistaken impression that it is impossible to use PartitionedSignal

the overall width of the *full* signal should be passed in as
an argument.

>     width = part_wid * part_count


width needs to an input parameter *to* layout(), not a
computed quantity, where part_wid is instead calculated
by division.

*then* Signals will end up at uniform predetermined lengths
and *then* straight assignment (wire-only  no muxes) can occur

if the underlying signal ends up varying by arbitrary lengths
determined by the pieces used, of *course* you can't wire them
up safely because tbey're all different total sizes.

fixing the length makes the power 2 alignment sizes all the same,
problem solved.

>     points = {}
>     for i, c in part_counts.items():
>         def add_p(p):
>             points[p] = points.get(p, False) | (elwid == i)

this needs to allocate the actual mask Signal, i'm not totally
sure how, with the length not yet being determined, hm.

>         for start in range(0, part_count, c):
>             add_p(start * part_wid) # start of lane
>             add_p(start * part_wid + lane_shapes[i].width) # start of padding
>     points.pop(0, None)
>     points.pop(width, None)

ok now the length is known, now a Signal(len(points))
can be created, then a bit each dropped into the values
in sequence order of its keys, end result just like

>     return (PartitionPoints(points), Shape(width, signed), lane_shapes,
>         part_wid, part_count)

Shape() is not needed because width is a given and signed is
not layout()'s responsibility.

here also the extra dict needs to be returned which gives
the options, "if you want elwidth=0b00, this is the
value you have to set in the PartitionPoints mask
to get that to happen"

> part_counts = {
>     0: 1,
>     1: 1,
>     2: 2,
>     3: 4,
> }

ok yeah, so you went with elwidth => num_of_partitions, cool.

> for i in range(4):
>     l = {0: signed(5), 1: signed(6), 2: signed(12), 3: signed(24)}
>     pprint((i, layout(i, part_counts, l)))

and a straight dict for length of subsignals (excl padding).
minus the signed() it is real dead simple.

the only thing being as i said, it produces different
overall widths depending on the input lane_shape which
is a showstopper.

if overall width (64 bit) is given as the input it fixes that.

does mean a safety check is needed, elwidth=0b11 means
4 partitions, 4 partitions of 24 bit obviously won't fit
in 64 bit!

You are receiving this mail because:
You are on the CC list for the bug.

More information about the libre-soc-bugs mailing list