[libre-riscv-dev] buffered pipeline

Luke Kenneth Casson Leighton lkcl at lkcl.net
Tue Mar 19 05:19:09 GMT 2019


On Tue, Mar 19, 2019 at 1:31 AM Jacob Lifshay <programmerjake at gmail.com> wrote:
>
> what do you think of the naming and structure used in
> https://salsa.debian.org/Kazan-team/simple-barrel-processor/blob/c2b3d40611225ca8a274a4bff36ac31ef7f4b64b/src/pipeline.py

 SignalGroup is a duplication of the nmigen Record class.  i just
managed to understand what Record is for, last night, after
encountering this, in hdl/ast.py Array's docstring:

    Array of records::

        layout = [
            ("re",     1),
            ("dat_r", 16),
        ]
        buses  = Array(Record(layout) for busno in range(4))
        master = Record(layout)
        m.d.comb += [
            buses[sel].re.eq(master.re),
            master.dat_r.eq(buses[sel].dat_r),
        ]

layout is basically signal_shapes.items()

StageIOBase, by being generic, doesn't have the i_ and o_ prefixes
(that make it a challenge to create generic, shared code) which also
has the side-effect of making it impossible to track and differentiate
prev/next inputs/outputs.

also, it's still complicated by the use of SignalGroup (aka Record).

with the "eq()" function convention, only 3 lines are needed, and both
PrevControl and NextControl are dead-simple (yes, i know it's possible
to use list *IN*comprehension to "simplify" eq below.  i call it list
*in*comprehension for a reason...)

def eq(o, i):
    if not isinstance(o, Sequence):
        o, i = [o], [i]
    res = []
    for (ao, ai) in zip(o, i):
        res.append(ao.eq(ai))
    return res

class PrevControl:
    def __init__(self):
        self.i_valid = Signal(name="p_i_valid") # >>in
        self.o_ready = Signal(name="p_o_ready") # <<out
    def connect_in(self, prev):
        return [self.i_valid.eq(prev.i_valid),
                prev.o_ready.eq(self.o_ready),
                eq(self.i_data, prev.i_data),
               ]

bottom line: StageIOBase is overengineered, and so is
connected_between_stages, which by using the "eq()" function
convention reduces down to 3 lines (above: see connect_in).

eq is used elsewhere, and could be adapted to take in a dictionary of
signals as well as a list/tuple.


also: compare the use of SignalGroup's capabilities to the use of eq.

* SignalGroup forces the user of the Pipeline module to use
StageToPred and StageToSucc (with a Record spec).  therefore, if using
a module or a class, it will be necessary to add additional code that
syncs the signals in and out.  in addition, if the user wants some
signals named "valid" or "ready", they're hosed.

* eq (as a convention) can be used on a single signal, a list of
signals, a class instance which happens to have an eq function (where
*its* responsibility is - by convention - to take care of copying all
Signals, which IN TURN may ALSO be class members).

 *AND*... i just took a look at dsl/rec.py - Record has an eq
function, because it derives from Value!  so, it will be possible to
use a Record instance as an input (or output) stage, and pass *that*
into eq as *well*.

to illustrate: i already have exactly such a Signal-copying function
in many of the IEEE754 FPU classes, it just happens to have been
called copy, and needs a global/search/replace "s/copy/eq" to conform
to the convention.

i'll try creating a Record example to make sure it works.

l.



More information about the libre-riscv-dev mailing list