[Libre-soc-bugs] [Bug 708] New: PartitionedSignal API design

bugzilla-daemon at libre-soc.org bugzilla-daemon at libre-soc.org
Thu Sep 23 22:06:32 BST 2021


https://bugs.libre-soc.org/show_bug.cgi?id=708

            Bug ID: 708
           Summary: PartitionedSignal API design
           Product: Libre-SOC's first SoC
           Version: unspecified
          Hardware: Other
                OS: Linux
            Status: CONFIRMED
          Severity: enhancement
          Priority: ---
         Component: Source Code
          Assignee: programmerjake at gmail.com
          Reporter: programmerjake at gmail.com
                CC: libre-soc-bugs at lists.libre-soc.org
            Blocks: 458
   NLnet milestone: ---

I think what we need to do is have the entire PartitionedSignal (and related)
API be more like SIMT -- where basically all operations operate in-parallel and
independently on each partition, including Cat, Mux, slicing, +, If, Switch,
Case, conversion from Signal (which I think should only happen explicitly via a
splat function/static-method, otherwise mixing PartitionedSignal and Signal
results in a type error), conversion from int, etc.

Essentially we treat a PartitionedSignal conceptually as a list of Signals
where all normal operations operate element-wise on each signal in the list.

I think this makes the code waay more readable and consistent.

There would be specially designated methods for converting the whole
PartitionedSignal from/to their underlying Signals (think of conceptually
concatenating all signals in a list together, or splitting a signal into a list
of signals).

PartitionedSignal would essentially end up being a list of Signals (not
literally, they would be pieces of a Signal), where the Signals could be either
dynamically sized or statically sized, the size would be chosen at runtime by
combinatorial logic (basically a small lookup table) based on a layout enum.
that layout enum (with the combinatorial logic) replaces PartitionPoints. This
allows things like:
class FPULayoutEnum(Enum):
    F16x4 = ...
    F32x2 = ...
    F64x1 = ...
exponent_field_layout = { # probably in a FP layout class
    FPULayoutEnum.F16x4: 5,
    FPULayoutEnum.F32x2: 8,
    FPULayoutEnum.F64x1: 11
}
exponent_field_slice = { # probably in a FP layout class
    FPULayoutEnum.F16x4: slice(10,16),
    FPULayoutEnum.F32x2: slice(23,32),
    FPULayoutEnum.F64x1: slice(52,64)
}
float_layout = { # probably next to FPULayoutEnum
    FPULayoutEnum.F16x4: 16,
    FPULayoutEnum.F32x2: 32,
    FPULayoutEnum.F64x1: 64
}

class MyFPUStage:
    def __init__(self):
        self.fpu_layout = Signal(FPULayoutEnum)
        with PartitionedSignal.layout_scope(self.fpu_layout):
            self.float_bits = PartitionedSignal(float_layout)
            self.exponent_field = PartitionedSignal(exponent_field_layout)
    def elaborate(self, ...):
        m = Module()
        with PartitionedSignal.layout_scope(self.fpu_layout):
            # generic over all float types! easy to read/think about!
            m.d.comb += exponent_field.eq(float_bits[exponent_field_slice])
            # do stuff with exponent_field...
        return m

This means PartitionedSignal would sometimes be partitioned in a more complex
way, such as if all partitions always have 5 bits (conceptually like [Signal(5)
for _ in ...]) -- there would need to be gaps in some cases.

For all examples:
a, b, and c are PartitionedSignal,
s is a Signal
v is a Python variable

Examples:
v = a + b # adding PartitionedSignal
conceptual equivalent:
v = [i + j for i, j in zip(a, b)]

v = a + splat(s)
conceptual equivalent:
v = [i + s for i in a]

v = a + s # adding PartitionedSignal and Signal
conceptual equivalent:
raise TypeError()

v = splat(s)
conceptual equivalent:
v = [s] * len(partitions)

v = Cat(a, b, c)
conceptual equivalent:
v = [Cat(i, j, k) for i, j, k in zip(a, b, c)]

v = Cat(a, s) # `Cat`ting PartitionedSignal and Signal
conceptual equivalent:
raise TypeError()


v = a[3:5]
conceptual equivalent:
v = [i[3:5] for i in a]

with m.Switch(a):
    with m.Case(3, 10, '--101'):
        m.d.comb += b.eq(23)
    with m.Default():
        m.d.comb += b.eq(45)
conceptual equivalent:
for i, j in zip(a, b):
    with m.Switch(i):
        with m.Case(3, 10, '--101'):
            m.d.comb += j.eq(23)
        with m.Default():
            m.d.comb += j.eq(45)

v = PartitionedSignal(underlying=s, partitions=...)
conceptual equivalent:
v = list(s.partitions()) # more or less...

v = a.underlying
conceptual equivalent:
v = Cat(*a) # more or less...


Referenced Bugs:

https://bugs.libre-soc.org/show_bug.cgi?id=458
[Bug 458] PartitionedSignal needs nmigen constructs "m.If", Switch etc
-- 
You are receiving this mail because:
You are on the CC list for the bug.


More information about the libre-soc-bugs mailing list