Begin adding floating point cordic pipeline
authorMichael Nolan <mtnolan2640@gmail.com>
Tue, 28 Apr 2020 17:21:20 +0000 (13:21 -0400)
committerMichael Nolan <mtnolan2640@gmail.com>
Mon, 4 May 2020 18:55:10 +0000 (14:55 -0400)
src/ieee754/cordic/fp_pipe_data.py [new file with mode: 0644]
src/ieee754/cordic/fp_pipe_init_stages.py [new file with mode: 0644]
src/ieee754/cordic/fp_pipeline.py [new file with mode: 0644]
src/ieee754/cordic/test/test_fp_pipe.py [new file with mode: 0644]

diff --git a/src/ieee754/cordic/fp_pipe_data.py b/src/ieee754/cordic/fp_pipe_data.py
new file mode 100644 (file)
index 0000000..25c70ff
--- /dev/null
@@ -0,0 +1,20 @@
+from nmigen import Signal, Const
+from nmutil.dynamicpipe import SimpleHandshakeRedir
+from ieee754.fpcommon.fpbase import FPNumBaseRecord
+from ieee754.pipeline import PipelineSpec
+from nmutil.concurrentunit import num_bits
+import math
+
+from ieee754.cordic.pipe_data import (CordicData, CordicInitialData,
+                                      CordicPipeSpec)
+
+
+class FPCordicPipeSpec(CordicPipeSpec, PipelineSpec):
+    def __init__(self, width, rounds_per_stage, num_rows):
+        rec = FPNumBaseRecord(width, False)
+        fracbits = 2 * rec.m_width
+        self.width = width
+        id_wid = num_bits(num_rows)
+        CordicPipeSpec.__init__(self, fracbits, rounds_per_stage)
+        PipelineSpec.__init__(self, width, op_wid=1, n_ops=1,
+                              id_width=id_wid)
diff --git a/src/ieee754/cordic/fp_pipe_init_stages.py b/src/ieee754/cordic/fp_pipe_init_stages.py
new file mode 100644 (file)
index 0000000..ab74006
--- /dev/null
@@ -0,0 +1,36 @@
+from nmigen import Module, Signal, Cat, Const, Mux
+from nmigen.cli import main, verilog
+
+from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord
+
+from nmutil.pipemodbase import PipeModBase
+from ieee754.fpcommon.basedata import FPBaseData
+from ieee754.fpcommon.denorm import FPSCData
+
+
+class FPCordicInitStage(PipeModBase):
+    def __init__(self, pspec):
+        super().__init__(pspec, "specialcases")
+
+    def ispec(self):
+        return FPBaseData(self.pspec)
+
+    def ospec(self):
+        return FPSCData(self.pspec, False)
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+
+        # decode a/b
+        width = self.pspec.width
+        a1 = FPNumBaseRecord(width, False)
+        m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
+        comb += [a1.v.eq(self.i.a),
+                 self.o.a.eq(a1)
+        ]
+
+        #  pass through context
+        comb += self.o.ctx.eq(self.i.ctx)
+
+        return m
diff --git a/src/ieee754/cordic/fp_pipeline.py b/src/ieee754/cordic/fp_pipeline.py
new file mode 100644 (file)
index 0000000..d6bf90a
--- /dev/null
@@ -0,0 +1,41 @@
+from nmutil.singlepipe import ControlBase
+from nmutil.pipemodbase import PipeModBaseChain
+
+from ieee754.fpcommon.denorm import FPAddDeNormMod
+from ieee754.cordic.fp_pipe_init_stages import (FPCordicInitStage)
+
+
+class CordicPipeChain(PipeModBaseChain):
+    def __init__(self, pspec, stages):
+        self.stages = stages
+        super().__init__(pspec)
+
+    def get_chain(self):
+        return self.stages
+
+
+class FPCordicBasePipe(ControlBase):
+    def __init__(self, pspec):
+        ControlBase.__init__(self)
+        self.pspec = pspec
+
+        self.denorm = CordicPipeChain(pspec,
+                                      [FPCordicInitStage(self.pspec),
+                                       FPAddDeNormMod(self.pspec, False)])
+
+        self._eqs = self.connect([self.denorm])
+
+    def chunkify(self, initstage, stages):
+        chunks = []
+
+        for i in range(0, len(stages), self.pspec.rounds_per_stage):
+            chunks.append(stages[i:i + self.pspec.rounds_per_stage])
+        chunks[0].insert(0, initstage)
+
+        return chunks
+
+    def elaborate(self, platform):
+        m = ControlBase.elaborate(self, platform)
+        m.submodules.denorm = self.denorm
+        m.d.comb += self._eqs
+        return m
diff --git a/src/ieee754/cordic/test/test_fp_pipe.py b/src/ieee754/cordic/test/test_fp_pipe.py
new file mode 100644 (file)
index 0000000..c75ef74
--- /dev/null
@@ -0,0 +1,64 @@
+from nmigen import Module, Signal
+from nmigen.back.pysim import Simulator, Passive
+from nmigen.test.utils import FHDLTestCase
+from nmigen.cli import rtlil
+from sfpy import Float32
+
+from ieee754.cordic.fp_pipeline import FPCordicBasePipe
+from ieee754.cordic.fp_pipe_data import FPCordicPipeSpec
+import unittest
+import math
+import random
+
+
+class SinCosTestCase(FHDLTestCase):
+    def run_test(self, inputs):
+        m = Module()
+        pspec = FPCordicPipeSpec(width=32, rounds_per_stage=4, num_rows=1)
+        m.submodules.dut = dut = FPCordicBasePipe(pspec)
+
+        for port in dut.ports():
+            print ("port", port)
+
+        # vl = rtlil.convert(dut, ports=dut.ports())
+        # with open("test_cordic_pipe_sin_cos.il", "w") as f:
+        #     f.write(vl)
+
+        z = Signal(dut.p.data_i.a.shape())
+        z_valid = Signal()
+        ready = Signal()
+
+        m.d.comb += [
+            dut.p.data_i.a.eq(z),
+            dut.p.valid_i.eq(z_valid),
+            dut.n.ready_i.eq(ready),
+            ]
+
+        sim = Simulator(m)
+        sim.add_clock(1e-6)
+
+        def writer_process():
+            for val in inputs:
+                print(val)
+                yield z.eq(val.bits)
+                yield z_valid.eq(1)
+                yield ready.eq(1)
+                yield
+
+        sim.add_sync_process(writer_process)
+        with sim.write_vcd("fp_pipeline.vcd", "fp_pipeline.gtkw", traces=[
+                z]):
+            sim.run()
+
+    def test_rand(self):
+        fracbits = 16
+        M = (1 << fracbits)
+        ZMAX = int(round(M * math.pi/2))
+        inputs = []
+        for i in range(10):
+            inputs.append(Float32(1.0*i))
+        self.run_test(iter(inputs))
+
+
+if __name__ == "__main__":
+    unittest.main()