[libre-riscv-dev] [Bug 64] data handling / io control / data routing API needed

bugzilla-daemon at libre-riscv.org bugzilla-daemon at libre-riscv.org
Sun Apr 28 12:25:32 BST 2019


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

> > * the use of the function create_data *on* an object - rather than being
> >   a function itself - forces a requirement on chaining of segments to
> >   provide an *intermediary* data object from which *both* the input
> >   object *and* the output object are forced to inherit.
> No, it doesn't actually. all it requires is that the output shape of the
> previous CombSeg == the input shape of the current CombSeg, which is a
> structural comparison, not identity.

 you may have misunderstood as i didn't give an example.  let me try
 to write one.  the issue is:

 * that there is only one name for the function that creates data.
 * that in creating a Chain of Blocks, each Block can no longer
   tell the chaining function which data is its input and which its output

 so a Stage (Block) is declared... except to be honest i cannot for the
 life of me see how to even start to do one Stage, let alone chain two

 which brings me on to something very important - a flaw in the proposed
 setup of EntryPort and ExitPort - that i missed before.

 i have encountered situations - usually involving modules - where it is
 NOT POSSIBLE to determine, at constructor time, what data is supposed to
 go into the Stage.

 the only way to know is during elaboration.

 yet, the elaborate function is clearly inappropriate for overloading as
 a constructor.

 in addition, i also encountered situations - again, involving modules -
 where constructing the data ***FAILS*** because the nmigen Modules on
 which it critically depends have not yet been set up.  only if those
 modules are correctly initialised during *elaboration* (and the data
 constructed at that time as well) will it work.

 *this is one of the many reasons i separated Data out from the I/O control*.

 def EntryPort
    def __init__(self, name: str):
--->    self.data_in = None # CAN ONLY BE SAFELY SET UP LATER  <----
        self.ready_out = Signal(1, name=name + "_ready_out")
        self.valid_in = Signal(1, reset=0, name=name + "_valid_in")

 so the subdivision of "labour" so to speak is:

 * A "convention" for Data [a generator with eventual yield of something
   that derives from Value.  yes that includes Consts!]

 * PrevControl for IO signalling to previous stage (no data involved)

 * NextControl for IO signalling to next stage (no data involved)

 * Stage API with ispec, ospec and process function for combinatorial block
   and specifying both the input data format and output data format

   NO IO SIGNALLING IS INVOLVED.  clean separation of data from IO

 * StageChain conforming to the same DATA-HANDLING-ONLY Stage API to
   chain (potentially hierarchically) Stages together

   NO IO SIGNALLING IS INVOLVED.  clean separation of data from IO

 * ControlBase which brings Stage (data) together with Prev and Next
   IO Control

   *THIS* is where IO signalling meets Data... yet they are still separate

 * ControlBase.connect for connecting chains of ControlBase instances together
   (creating actual multi-stage pipelines in the process)

 * Derivatives of ControlBase actually manage the prev/next sync, and
   pass data around, taking care of when it is "processed", according to
   the design of that *derivative*... *NOT* when the *STAGE* decides data

 you are proposing:

 * Data for mandatory control of data formats (module or class)

 * Shape for mandatory restriction of data allocation through one and only
   one specifically-named member function of Data (create_data).

 * EntryPort for IO signalling to previous stage *AND* allocation of DATA
   (which will fail under certain circumstances)

 * ExitPort for IO signalling to next stage *AND* allocation of DATA
   (which will fail under certain circumstances)

 * CombSeg for bringing previous and next data together (despite the
   fact that Block *ALSO* brings data together).


 * CombSegFn for providing a means of (combinatorially) linking input data
   to processing to output.

   This is basically functionally directly equivalent to the Stage API
   (except that it is mandatory that it be a nmigen module, where the
    Stage API permits non-module scenarios, hence the difference between
    Stage.process and Stage.setup)

 * Block for bringing EntryPort and ExitPort together (despite CombSeg
   already *having* Data)

 * CombBlock as a really unclear (and unnecessary) workaround for CombSeg
   already having in/out Data...

the proposed API goes awry in several places:

* certain Blocks may wish to pre-process or post-process, depending on
  design.  CombSegFn prevents and prohibits that decision-making process
  by *BLOCKS THEMSELVES* - by *design*

* Entry/ExitPort creating data in the constructor runs into difficulties
  with nmigen module elaboration

* several design restrictions which limit the scope of possibilities.

* a workaround (Block.wrap) for double-allocation (by design) of data,
  where only one class is strictly necessary to take responsibility for
  data emplacement.

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

More information about the libre-riscv-dev mailing list