+++ /dev/null
-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)
-
--- /dev/null
+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)
+
--- /dev/null
+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()