From f0f94e4e12933831d84203c7fd86e38e19e34838 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Wed, 31 Jul 2019 15:31:05 +0100 Subject: [PATCH] move DynamicPipe to nmutil --- src/ieee754/pipeline.py | 73 +------------------------------------ src/nmutil/dynamicpipe.py | 76 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 72 deletions(-) create mode 100644 src/nmutil/dynamicpipe.py diff --git a/src/ieee754/pipeline.py b/src/ieee754/pipeline.py index 17cde15a..8a9c408c 100644 --- a/src/ieee754/pipeline.py +++ b/src/ieee754/pipeline.py @@ -1,11 +1,8 @@ # SPDX-License-Identifier: LGPL-2.1-or-later # See Notices.txt for copyright information -from abc import ABCMeta -from nmigen import Elaboratable - from nmutil.singlepipe import SimpleHandshake -import threading +from nmutil.dynamicpipe import DynamicPipe, SimpleHandshakeRedir class PipelineSpec: @@ -37,71 +34,3 @@ class PipelineSpec: self.fpformat = None self.n_comb_stages = None -# with many thanks to jsbueno on stackexchange for this one -# https://stackoverflow.com/questions/57273070/ -# list post: -# http://lists.libre-riscv.org/pipermail/libre-riscv-dev/2019-July/002259.html - -class Meta(ABCMeta): - registry = {} - recursing = threading.local() - recursing.check = False - mlock = threading.Lock() - - def __call__(cls, *args, **kw): - mcls = cls.__class__ - if mcls.recursing.check: - return super().__call__(*args, **kw) - spec = args[0] - base = spec.pipekls # pick up the dynamic class from PipelineSpec, HERE - - if (cls, base) not in mcls.registry: - print ("__call__", args, kw, cls, base, - base.__bases__, cls.__bases__) - mcls.registry[cls, base] = type( - cls.__name__, - (cls, base) + cls.__bases__[1:], - {} - ) - real_cls = mcls.registry[cls, base] - - with mcls.mlock: - mcls.recursing.check = True - instance = real_cls.__class__.__call__(real_cls, *args, **kw) - mcls.recursing.check = False - return instance - - -# Inherit from this class instead of SimpleHandshake (or other ControlBase -# derivative), and the metaclass will instead *replace* DynamicPipe - -# *at runtime* - with the class that is specified *as a parameter* -# in PipelineSpec. -# -# as explained in the list posting and in the stackexchange post, this is -# needed to avoid a MASSIVE suite of duplicated multiple-inheritance classes -# that "Mix in" SimpleHandshake (or other). -# -# unfortunately, composition does not work in this instance -# (make an *instance* of SimpleHandshake or other class and pass it in) -# due to the multiple level inheritance, and in several places -# the inheriting class needs to do some setup that the deriving class -# needs in order to function correctly. - -class DynamicPipe(metaclass=Meta): - def __init__(self, *args): - print ("DynamicPipe init", super(), args) - super().__init__(self, *args) - - -# bad hack: the DynamicPipe metaclass ends up creating an __init__ signature -# for the dynamically-derived class. luckily, SimpleHandshake only needs -# "self" as the 1st argument (it is its own "Stage"). anything else -# could hypothetically be passed through the pspec. -class SimpleHandshakeRedir(SimpleHandshake): - def __init__(self, mod, *args): - print ("redir", mod, args) - stage = self - if args and args[0].stage: - stage = args[0].stage - SimpleHandshake.__init__(self, stage) - diff --git a/src/nmutil/dynamicpipe.py b/src/nmutil/dynamicpipe.py new file mode 100644 index 00000000..01a3f99e --- /dev/null +++ b/src/nmutil/dynamicpipe.py @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# See Notices.txt for copyright information + +from abc import ABCMeta + +from nmutil.singlepipe import SimpleHandshake +import threading + +# with many thanks to jsbueno on stackexchange for this one +# https://stackoverflow.com/questions/57273070/ +# list post: +# http://lists.libre-riscv.org/pipermail/libre-riscv-dev/2019-July/002259.html + +class Meta(ABCMeta): + registry = {} + recursing = threading.local() + recursing.check = False + mlock = threading.Lock() + + def __call__(cls, *args, **kw): + mcls = cls.__class__ + if mcls.recursing.check: + return super().__call__(*args, **kw) + spec = args[0] + base = spec.pipekls # pick up the dynamic class from PipelineSpec, HERE + + if (cls, base) not in mcls.registry: + print ("__call__", args, kw, cls, base, + base.__bases__, cls.__bases__) + mcls.registry[cls, base] = type( + cls.__name__, + (cls, base) + cls.__bases__[1:], + {} + ) + real_cls = mcls.registry[cls, base] + + with mcls.mlock: + mcls.recursing.check = True + instance = real_cls.__class__.__call__(real_cls, *args, **kw) + mcls.recursing.check = False + return instance + + +# Inherit from this class instead of SimpleHandshake (or other ControlBase +# derivative), and the metaclass will instead *replace* DynamicPipe - +# *at runtime* - with the class that is specified *as a parameter* +# in PipelineSpec. +# +# as explained in the list posting and in the stackexchange post, this is +# needed to avoid a MASSIVE suite of duplicated multiple-inheritance classes +# that "Mix in" SimpleHandshake (or other). +# +# unfortunately, composition does not work in this instance +# (make an *instance* of SimpleHandshake or other class and pass it in) +# due to the multiple level inheritance, and in several places +# the inheriting class needs to do some setup that the deriving class +# needs in order to function correctly. + +class DynamicPipe(metaclass=Meta): + def __init__(self, *args): + print ("DynamicPipe init", super(), args) + super().__init__(self, *args) + + +# bad hack: the DynamicPipe metaclass ends up creating an __init__ signature +# for the dynamically-derived class. luckily, SimpleHandshake only needs +# "self" as the 1st argument (it is its own "Stage"). anything else +# could hypothetically be passed through the pspec. +class SimpleHandshakeRedir(SimpleHandshake): + def __init__(self, mod, *args): + print ("redir", mod, args) + stage = self + if args and args[0].stage: + stage = args[0].stage + SimpleHandshake.__init__(self, stage) + -- 2.30.2