From 9d91ad05b8944ea652cfd4f050dbe6837e4332f8 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Wed, 31 Jul 2019 00:14:12 +0100 Subject: [PATCH] resolve awful meta-class hacking (with thanks to jsbueno on stackexchange) --- src/ieee754/fpadd/addstages.py | 11 +++---- src/ieee754/pipeline.py | 59 ++++++++++++++++++++++++++++------ src/nmutil/singlepipe.py | 3 +- 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/ieee754/fpadd/addstages.py b/src/ieee754/fpadd/addstages.py index 2bc23df0..f875ef92 100644 --- a/src/ieee754/fpadd/addstages.py +++ b/src/ieee754/fpadd/addstages.py @@ -5,8 +5,8 @@ from nmigen import Module from nmigen.cli import main, verilog -from nmutil.singlepipe import (StageChain, SimpleHandshake, - PassThroughStage) +from nmutil.singlepipe import StageChain +from ieee754.pipeline import DynamicPipe from ieee754.fpcommon.fpbase import FPState from ieee754.fpcommon.denorm import FPSCData @@ -15,13 +15,12 @@ from ieee754.fpadd.align import FPAddAlignSingleMod from ieee754.fpadd.add0 import FPAddStage0Mod from ieee754.fpadd.add1 import FPAddStage1Mod - -class FPAddAlignSingleAdd(FPState, SimpleHandshake): +class FPAddAlignSingleAdd(DynamicPipe): def __init__(self, pspec): - FPState.__init__(self, "align") + #FPState.__init__(self, "align") self.pspec = pspec - SimpleHandshake.__init__(self, self) # pipeline is its own stage + super().__init__(pspec) self.a1o = self.ospec() def ispec(self): diff --git a/src/ieee754/pipeline.py b/src/ieee754/pipeline.py index b1e3b0ba..2e572459 100644 --- a/src/ieee754/pipeline.py +++ b/src/ieee754/pipeline.py @@ -1,7 +1,11 @@ # 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 class PipelineSpec: @@ -27,18 +31,55 @@ class PipelineSpec: self.id_wid = id_width self.op_wid = op_wid self.opkls = opkls - self.pipekls = pipekls or SimpleHandshake + self.pipekls = pipekls or SimpleHandshakeRedir self.core_config = None self.fpformat = None self.n_comb_stages = None +# with many thanks to jsbueno on stackexchange for this one +# https://stackoverflow.com/questions/57273070/ + +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 + + 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 + + +class DynamicPipe(metaclass=Meta): + def __init__(self, *args): + print ("DynamicPipe init", super(), args) + super().__init__(self, *args) + -def DynamicPipeCreate(pspec, *args, **kwargs): - superclass = pspec.pipekls - class DynamicPipe(superclass): - def __init__(self, *args, **kwargs): - print(superclass) - superclass.__init__(self, *args, **kwargs) - pass - return DynamicPipe(*args, **kwargs) +# 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, pspec, *args): + print ("redir", pspec, args) + SimpleHandshake.__init__(self, self) diff --git a/src/nmutil/singlepipe.py b/src/nmutil/singlepipe.py index b9214bd5..8a5b06dc 100644 --- a/src/nmutil/singlepipe.py +++ b/src/nmutil/singlepipe.py @@ -138,7 +138,7 @@ import inspect from nmutil.iocontrol import (PrevControl, NextControl, Object, RecordObject) from nmutil.stageapi import (_spec, StageCls, Stage, StageChain, StageHelper) from nmutil import nmoperator - + class RecordBasedStage(Stage): """ convenience class which provides a Records-based layout. @@ -190,6 +190,7 @@ class ControlBase(StageHelper, Elaboratable): * add data_o member to NextControl (n) Calling ControlBase._new_data is a good way to do that. """ + print ("ControlBase", self, stage, in_multi, stage_ctl) StageHelper.__init__(self, stage) # set up input and output IO ACK (prev/next ready/valid) -- 2.30.2