1 # SPDX-License-Identifier: LGPL-2.1-or-later
2 # See Notices.txt for copyright information
4 from abc
import ABCMeta
5 from nmigen
import Elaboratable
7 from nmutil
.singlepipe
import SimpleHandshake
12 """ Pipeline Specification base class.
14 :attribute width: the IEEE754 FP bitwidth
15 :attribute id_wid: the Reservation Station muxid bitwidth
16 :attribute op_wid: an "operand bitwidth" passed down all stages
17 :attribute opkls: an optional class that is instantiated as the "operand"
19 See ieee754/fpcommon/getop FPPipeContext for how (where) PipelineSpec
20 is used. FPPipeContext is passed down *every* stage of a pipeline
21 and contains the Reservation Station multiplexer ID as well as
22 an optional "operand". This "operand" may be used to *change*
23 the behaviour of the pipeline. In RISC-V terminology it would
24 typically be set to e.g. funct7 or parts thereof.
28 def __init__(self
, width
, id_width
, op_wid
=0, opkls
=None, pipekls
=None):
29 """ Create a PipelineSpec. """
31 self
.id_wid
= id_width
34 self
.pipekls
= pipekls
or SimpleHandshakeRedir
35 self
.core_config
= None
37 self
.n_comb_stages
= None
39 # with many thanks to jsbueno on stackexchange for this one
40 # https://stackoverflow.com/questions/57273070/
42 # http://lists.libre-riscv.org/pipermail/libre-riscv-dev/2019-July/002259.html
46 recursing
= threading
.local()
47 recursing
.check
= False
48 mlock
= threading
.Lock()
50 def __call__(cls
, *args
, **kw
):
52 if mcls
.recursing
.check
:
53 return super().__call
__(*args
, **kw
)
55 base
= spec
.pipekls
# pick up the dynamic class from PipelineSpec, HERE
57 if (cls
, base
) not in mcls
.registry
:
58 print ("__call__", args
, kw
, cls
, base
, base
.__bases
__, cls
.__bases
__)
59 mcls
.registry
[cls
, base
] = type(
61 (cls
, base
) + cls
.__bases
__[1:],
64 real_cls
= mcls
.registry
[cls
, base
]
67 mcls
.recursing
.check
= True
68 instance
= real_cls
.__class
__.__call
__(real_cls
, *args
, **kw
)
69 mcls
.recursing
.check
= False
73 # Inherit from this class instead of SimpleHandshake (or other ControlBase
74 # derivative), and the metaclass will instead *replace* DynamicPipe -
75 # *at runtime* - with the class that is specified *as a parameter*
78 # as explained in the list posting and in the stackexchange post, this is
79 # needed to avoid a MASSIVE suite of duplicated multiple-inheritance classes
80 # that "Mix in" SimpleHandshake (or other).
82 # unfortunately, composition does not work in this instance
83 # (make an *instance* of SimpleHandshake or other class and pass it in)
84 # due to the multiple level inheritance, and in several places
85 # the inheriting class needs to do some setup that the deriving class
86 # needs in order to function correctly.
88 class DynamicPipe(metaclass
=Meta
):
89 def __init__(self
, *args
):
90 print ("DynamicPipe init", super(), args
)
91 super().__init
__(self
, *args
)
94 # bad hack: the DynamicPipe metaclass ends up creating an __init__ signature
95 # for the dynamically-derived class. luckily, SimpleHandshake only needs
96 # "self" as the 1st argument (it is its own "Stage"). anything else
97 # could hypothetically be passed through the pspec.
98 class SimpleHandshakeRedir(SimpleHandshake
):
99 def __init__(self
, pspec
, *args
):
100 print ("redir", pspec
, args
)
101 SimpleHandshake
.__init
__(self
, self
)