1 # SPDX-License-Identifier: LGPL-2.1-or-later
2 # See Notices.txt for copyright information
4 from abc
import ABCMeta
6 from nmutil
.singlepipe
import SimpleHandshake
9 # with many thanks to jsbueno on stackexchange for this one
10 # https://stackoverflow.com/questions/57273070/
12 # http://lists.libre-riscv.org/pipermail/libre-riscv-dev/2019-July/002259.html
16 recursing
= threading
.local()
17 recursing
.check
= False
18 mlock
= threading
.Lock()
20 def __call__(cls
, *args
, **kw
):
22 if mcls
.recursing
.check
:
23 return super().__call
__(*args
, **kw
)
25 base
= spec
.pipekls
# pick up the dynamic class from PipelineSpec, HERE
27 if (cls
, base
) not in mcls
.registry
:
28 print ("__call__", args
, kw
, cls
, base
,
29 base
.__bases
__, cls
.__bases
__)
30 mcls
.registry
[cls
, base
] = type(
32 (cls
, base
) + cls
.__bases
__[1:],
35 real_cls
= mcls
.registry
[cls
, base
]
38 mcls
.recursing
.check
= True
39 instance
= real_cls
.__class
__.__call
__(real_cls
, *args
, **kw
)
40 mcls
.recursing
.check
= False
44 # Inherit from this class instead of SimpleHandshake (or other ControlBase
45 # derivative), and the metaclass will instead *replace* DynamicPipe -
46 # *at runtime* - with the class that is specified *as a parameter*
49 # as explained in the list posting and in the stackexchange post, this is
50 # needed to avoid a MASSIVE suite of duplicated multiple-inheritance classes
51 # that "Mix in" SimpleHandshake (or other).
53 # unfortunately, composition does not work in this instance
54 # (make an *instance* of SimpleHandshake or other class and pass it in)
55 # due to the multiple level inheritance, and in several places
56 # the inheriting class needs to do some setup that the deriving class
57 # needs in order to function correctly.
59 class DynamicPipe(metaclass
=Meta
):
60 def __init__(self
, *args
):
61 print ("DynamicPipe init", super(), args
)
62 super().__init
__(self
, *args
)
65 # bad hack: the DynamicPipe metaclass ends up creating an __init__ signature
66 # for the dynamically-derived class. luckily, SimpleHandshake only needs
67 # "self" as the 1st argument (it is its own "Stage"). anything else
68 # could hypothetically be passed through the pspec.
69 class SimpleHandshakeRedir(SimpleHandshake
):
70 def __init__(self
, mod
, *args
):
71 print ("redir", mod
, args
)
73 if args
and args
[0].stage
:
75 SimpleHandshake
.__init
__(self
, stage
)