Add test for sin_cos.py
authorMichael Nolan <mtnolan2640@gmail.com>
Tue, 31 Mar 2020 19:47:52 +0000 (15:47 -0400)
committerMichael Nolan <mtnolan2640@gmail.com>
Tue, 31 Mar 2020 19:47:52 +0000 (15:47 -0400)
src/ieee754/cordic/fptan.py [deleted file]
src/ieee754/cordic/sin_cos.py [new file with mode: 0644]
src/ieee754/cordic/test/test_sincos.py [new file with mode: 0644]

diff --git a/src/ieee754/cordic/fptan.py b/src/ieee754/cordic/fptan.py
deleted file mode 100644 (file)
index d3f54cc..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-from nmigen import Module, Elaboratable, Signal, Cat, Mux
-from nmigen.cli import rtlil
-import math
-from enum import Enum, unique
-
-class CordicState(Enum):
-    WAITING = 0
-    RUNNING = 1
-
-
-class CORDIC(Elaboratable):
-    def __init__(self, fracbits):
-        self.fracbits = fracbits
-        self.M = M = (1<<fracbits)
-        self.ZMAX = ZMAX = int(round(self.M * math.pi/2))
-
-        # sin/cos output in 0.ffffff format
-        self.cos = Signal(range(-M, M-1))
-        self.sin = Signal(range(-M, M-1))
-        # angle input
-        self.z0 = Signal(range(-ZMAX, ZMAX), reset_less=True)
-
-        # cordic start flag
-        self.start = Signal(reset_less=True)
-        # cordic done/ready for input
-        self.ready = Signal()
-
-        self.width = self.z0.width
-        self.iterations = self.width - 1
-
-    def elaborate(self, platform):
-        m = Module()
-        comb = m.d.comb
-        sync = m.d.sync
-        # Calculate initial amplitude?
-        An = 1.0
-        for i in range(self.iterations):
-            An *= math.sqrt(1 + 2**(-2*i))
-
-        X0 = int(round(self.M*1/An))
-        angles = [int(round(self.M*math.atan(2**(-i))))
-                  for i in range(self.iterations)]
-
-        x = Signal(self.sin.shape())
-        y = Signal(self.sin.shape())
-        z = Signal(self.z0.shape())
-        dx = Signal(self.sin.shape())
-        dy = Signal(self.sin.shape())
-        dz = Signal(self.z0.shape())
-        i = Signal(range(self.iterations))
-        
-        state = Signal(CordicState)
-
-        with m.If(state == CordicState.WAITING):
-            with m.If(self.start):
-                sync += x.eq(X0)
-                sync += y.eq(0)
-                sync += z.eq(self.z0)
-                sync += i.eq(0)
-                sync += self.ready.eq(0)
-                sync += state.eq(CordicState.RUNNING)
-        with m.If(state == CordicState.RUNNING):
-            sync += dx.eq(x >> i)
-            sync += dx.eq(y >> i)
-
-        return m
-    def ports(self):
-        return [self.cos, self.sin, self.z0,
-                self.ready, self.start]
-
-if __name__ == '__main__':
-    dut = CORDIC(8)
-    vl = rtlil.convert(dut, ports=dut.ports())
-    with open("cordic.il", "w") as f:
-        f.write(vl)
-
diff --git a/src/ieee754/cordic/sin_cos.py b/src/ieee754/cordic/sin_cos.py
new file mode 100644 (file)
index 0000000..7e72808
--- /dev/null
@@ -0,0 +1,113 @@
+from nmigen import Module, Elaboratable, Signal, Memory
+from nmigen.cli import rtlil
+import math
+from enum import Enum, unique
+
+
+@unique
+class CordicState(Enum):
+    WAITING = 0
+    RUNNING = 1
+
+
+class CordicROM(Elaboratable):
+    def __init__(self, fracbits, iterations):
+        self.fracbits = fracbits
+        self.iterations = iterations
+
+        M = 1 << fracbits
+        self.addr = Signal(range(iterations))
+        self.data = Signal(range(-M, M-1))
+
+        angles = [int(round(M*math.atan(2**(-i))))
+                  for i in range(self.iterations)]
+
+        self.mem = Memory(width=self.data.width,
+                          depth=self.iterations,
+                          init=angles)
+
+    def elaborate(self, platform):
+        m = Module()
+        m.submodules.rdport = rdport = self.mem.read_port()
+        m.d.comb += rdport.addr.eq(self.addr)
+        m.d.comb += self.data.eq(rdport.data)
+        return m
+
+
+class CORDIC(Elaboratable):
+    def __init__(self, fracbits):
+        self.fracbits = fracbits
+        self.M = M = (1 << fracbits)
+        self.ZMAX = ZMAX = int(round(self.M * math.pi/2))
+
+        # sin/cos output in 0.ffffff format
+        self.cos = Signal(range(-M, M-1))
+        self.sin = Signal(range(-M, M-1))
+        # angle input
+        self.z0 = Signal(range(-ZMAX, ZMAX), reset_less=True)
+
+        # cordic start flag
+        self.start = Signal(reset_less=True)
+        # cordic done/ready for input
+        self.ready = Signal()
+
+        self.width = self.z0.width
+        self.iterations = self.width - 1
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+        sync = m.d.sync
+
+
+        # Calculate initial amplitude?
+        An = 1.0
+        for i in range(self.iterations):
+            An *= math.sqrt(1 + 2**(-2*i))
+
+        X0 = int(round(self.M*1/An))
+        x = Signal(self.sin.shape())
+        y = Signal(self.sin.shape())
+        z = Signal(self.z0.shape())
+        dx = Signal(self.sin.shape())
+        dy = Signal(self.sin.shape())
+        dz = Signal(self.z0.shape())
+        i = Signal(range(self.iterations))
+        
+        state = Signal(CordicState)
+
+        m.submodules.anglerom = anglerom = \
+            CordicROM(self.fracbits, self.iterations)
+        comb += anglerom.addr.eq(i)
+
+        with m.If(state == CordicState.WAITING):
+            with m.If(self.start):
+                sync += x.eq(X0)
+                sync += y.eq(0)
+                sync += z.eq(self.z0)
+                sync += i.eq(0)
+                sync += self.ready.eq(0)
+                sync += state.eq(CordicState.RUNNING)
+        with m.If(state == CordicState.RUNNING):
+            sync += dx.eq(x >> i)
+            sync += dx.eq(y >> i)
+            sync += dz.eq(anglerom.data)
+            with m.If(i == self.iterations - 1):
+                sync += self.cos.eq(x)
+                sync += self.sin.eq(y)
+                sync += state.eq(CordicState.WAITING)
+                sync += self.ready.eq(1)
+            with m.Else():
+                sync += i.eq(i+1)
+        return m
+
+    def ports(self):
+        return [self.cos, self.sin, self.z0,
+                self.ready, self.start]
+
+if __name__ == '__main__':
+    dut = CORDIC(8)
+    vl = rtlil.convert(dut, ports=dut.ports())
+    with open("cordic.il", "w") as f:
+        f.write(vl)
+
diff --git a/src/ieee754/cordic/test/test_sincos.py b/src/ieee754/cordic/test/test_sincos.py
new file mode 100644 (file)
index 0000000..07ebc80
--- /dev/null
@@ -0,0 +1,41 @@
+from nmigen import Module, Signal
+from nmigen.back.pysim import Simulator, Delay
+from nmigen.test.utils import FHDLTestCase
+
+from ieee754.cordic.sin_cos import CORDIC
+import unittest
+
+class SinCosTestCase(FHDLTestCase):
+    def test_sincos(self):
+        m = Module()
+
+        fracbits = 8
+
+        m.submodules.dut = dut = CORDIC(fracbits)
+        z = Signal(dut.z0.shape())
+        start = Signal()
+
+        sin = Signal(dut.sin.shape())
+        cos = Signal(dut.cos.shape())
+        ready = Signal()
+
+        m.d.comb += [
+            dut.z0.eq(z),
+            dut.start.eq(start),
+            sin.eq(dut.sin),
+            cos.eq(dut.cos),
+            ready.eq(dut.ready)]
+
+        sim = Simulator(m)
+        sim.add_clock(1e-6)
+
+        def process():
+            for i in range(10):
+                yield
+        sim.add_sync_process(process)
+        with sim.write_vcd("sin_cos.vcd", "sin_cos.gtkw", traces=[
+                z, cos, sin, ready, start]):
+            sim.run()
+
+if __name__ == "__main__":
+    unittest.main()