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
36 self
.core_config
= None
38 self
.n_comb_stages
= None
40 # with many thanks to jsbueno on stackexchange for this one
41 # https://stackoverflow.com/questions/57273070/
43 # http://lists.libre-riscv.org/pipermail/libre-riscv-dev/2019-July/002259.html
47 recursing
= threading
.local()
48 recursing
.check
= False
49 mlock
= threading
.Lock()
51 def __call__(cls
, *args
, **kw
):
53 if mcls
.recursing
.check
:
54 return super().__call
__(*args
, **kw
)
56 base
= spec
.pipekls
# pick up the dynamic class from PipelineSpec, HERE
58 if (cls
, base
) not in mcls
.registry
:
59 print ("__call__", args
, kw
, cls
, base
, base
.__bases
__, cls
.__bases
__)
60 mcls
.registry
[cls
, base
] = type(
62 (cls
, base
) + cls
.__bases
__[1:],
65 real_cls
= mcls
.registry
[cls
, base
]
68 mcls
.recursing
.check
= True
69 instance
= real_cls
.__class
__.__call
__(real_cls
, *args
, **kw
)
70 mcls
.recursing
.check
= False
74 # Inherit from this class instead of SimpleHandshake (or other ControlBase
75 # derivative), and the metaclass will instead *replace* DynamicPipe -
76 # *at runtime* - with the class that is specified *as a parameter*
79 # as explained in the list posting and in the stackexchange post, this is
80 # needed to avoid a MASSIVE suite of duplicated multiple-inheritance classes
81 # that "Mix in" SimpleHandshake (or other).
83 # unfortunately, composition does not work in this instance
84 # (make an *instance* of SimpleHandshake or other class and pass it in)
85 # due to the multiple level inheritance, and in several places
86 # the inheriting class needs to do some setup that the deriving class
87 # needs in order to function correctly.
89 class DynamicPipe(metaclass
=Meta
):
90 def __init__(self
, *args
):
91 print ("DynamicPipe init", super(), args
)
92 super().__init
__(self
, *args
)
95 # bad hack: the DynamicPipe metaclass ends up creating an __init__ signature
96 # for the dynamically-derived class. luckily, SimpleHandshake only needs
97 # "self" as the 1st argument (it is its own "Stage"). anything else
98 # could hypothetically be passed through the pspec.
99 class SimpleHandshakeRedir(SimpleHandshake
):
100 def __init__(self
, mod
, *args
):
101 print ("redir", mod
, args
)
103 if args
and args
[0].stage
:
104 stage
= args
[0].stage
105 SimpleHandshake
.__init
__(self
, stage
)