add pipeline class and example
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 16 Feb 2019 07:02:06 +0000 (07:02 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 16 Feb 2019 07:02:06 +0000 (07:02 +0000)
src/add/pipeline.py [new file with mode: 0644]
src/add/pipeline_example.py [new file with mode: 0644]

diff --git a/src/add/pipeline.py b/src/add/pipeline.py
new file mode 100644 (file)
index 0000000..bf35b6b
--- /dev/null
@@ -0,0 +1,53 @@
+""" Example 5: Making use of PyRTL and Introspection. """
+
+from nmigen import Signal
+from nmigen.compat.fhdl.bitcontainer import value_bits_sign
+
+# The following example shows how pyrtl can be used to make some interesting
+# hardware structures using python introspection.  In particular, this example
+# makes a N-stage pipeline structure.  Any specific pipeline is then a derived
+# class of SimplePipeline where methods with names starting with "stage" are
+# stages, and new members with names not starting with "_" are to be registered
+# for the next stage.
+
+class SimplePipeline(object):
+    """ Pipeline builder with auto generation of pipeline registers.
+    """
+
+    def __init__(self, pipe):
+        self._pipe = pipe
+        self._pipeline_register_map = {}
+        self._current_stage_num = 0
+
+    def _setup(self):
+        stage_list = []
+        for method in dir(self):
+            if method.startswith('stage'):
+                stage_list.append(method)
+        for stage in sorted(stage_list):
+            stage_method = getattr(self, stage)
+            stage_method()
+            self._current_stage_num += 1
+
+    def __getattr__(self, name):
+        try:
+            return self._pipeline_register_map[self._current_stage_num][name]
+        except KeyError:
+            raise AttributeError(
+                'error, no pipeline register "%s" defined for stage %d'
+                % (name, self._current_stage_num))
+
+    def __setattr__(self, name, value):
+        if name.startswith('_'):
+            # do not do anything tricky with variables starting with '_'
+            object.__setattr__(self, name, value)
+        else:
+            next_stage = self._current_stage_num + 1
+            pipereg_id = str(self._current_stage_num) + 'to' + str(next_stage)
+            rname = 'pipereg_' + pipereg_id + '_' + name
+            new_pipereg = Signal(value_bits_sign(value), name=rname)
+            if next_stage not in self._pipeline_register_map:
+                self._pipeline_register_map[next_stage] = {}
+            self._pipeline_register_map[next_stage][name] = new_pipereg
+            self._pipe.sync += new_pipereg.eq(value)
+
diff --git a/src/add/pipeline_example.py b/src/add/pipeline_example.py
new file mode 100644 (file)
index 0000000..2198523
--- /dev/null
@@ -0,0 +1,51 @@
+""" Example 5: Making use of PyRTL and Introspection. """
+
+from copy import deepcopy
+from nmigen import Module, Signal
+from nmigen.cli import main, verilog
+
+
+from pipeline import SimplePipeline
+
+
+class SimplePipelineExample(SimplePipeline):
+    """ A very simple pipeline to show how registers are inferred. """
+
+    def __init__(self, pipe):
+        SimplePipeline.__init__(self, pipe)
+        self._loopback = Signal(4)
+        self._setup()
+
+    def stage0(self):
+        self.n = ~self._loopback
+
+    def stage1(self):
+        self.n = self.n + 1
+
+    def stage2(self):
+        self.n = self.n << 1
+
+    def stage3(self):
+        self.n = ~self.n
+
+    def stage4(self):
+        self._pipe.sync += self._loopback.eq(self.n + 3)
+
+class PipeModule:
+
+    def __init__(self):
+        self.m = Module()
+        self.p = SimplePipelineExample(self.m.d)
+
+    def get_fragment(self, platform=None):
+        return self.m
+
+if __name__ == "__main__":
+    example = PipeModule()
+    main(example, ports=[
+                    example.p._loopback,
+        ])
+
+    print(verilog.convert(example, ports=[ 
+               example.p._loopback,
+             ]))