sin/cos cordic partially working
[ieee754fpu.git] / src / ieee754 / cordic / sin_cos.py
1 from nmigen import Module, Elaboratable, Signal, Memory, signed
2 from nmigen.cli import rtlil
3 import math
4 from enum import Enum, unique
5
6
7 @unique
8 class CordicState(Enum):
9 WAITING = 0
10 RUNNING = 1
11
12
13 class CordicROM(Elaboratable):
14 def __init__(self, fracbits, iterations):
15 self.fracbits = fracbits
16 self.iterations = iterations
17
18 M = 1 << fracbits
19 self.addr = Signal(range(iterations))
20 self.data = Signal(range(-M, M-1))
21
22 angles = [int(round(M*math.atan(2**(-i))))
23 for i in range(self.iterations)]
24
25 self.mem = Memory(width=self.data.width,
26 depth=self.iterations,
27 init=angles)
28
29 def elaborate(self, platform):
30 m = Module()
31 m.submodules.rdport = rdport = self.mem.read_port()
32 m.d.comb += rdport.addr.eq(self.addr)
33 m.d.comb += self.data.eq(rdport.data)
34 return m
35
36
37 class CORDIC(Elaboratable):
38 def __init__(self, fracbits):
39 self.fracbits = fracbits
40 self.M = M = (1 << fracbits)
41 self.ZMAX = ZMAX = int(round(self.M * math.pi/2))
42
43 # sin/cos output in 0.ffffff format
44 self.cos = Signal(range(-M, M-1), reset=0)
45 self.sin = Signal(range(-M, M-1), reset=0)
46 # angle input
47 self.z0 = Signal(range(-ZMAX, ZMAX), reset_less=True)
48
49 # cordic start flag
50 self.start = Signal(reset_less=True)
51 # cordic done/ready for input
52 self.ready = Signal(reset=True)
53
54 self.width = self.z0.width
55 self.iterations = self.width - 1
56
57 def elaborate(self, platform):
58 m = Module()
59 comb = m.d.comb
60 sync = m.d.sync
61
62
63 # Calculate initial amplitude?
64 An = 1.0
65 for i in range(self.iterations):
66 An *= math.sqrt(1 + 2**(-2*i))
67
68 X0 = int(round(self.M*1/An))
69 x = Signal(self.sin.shape())
70 y = Signal(self.sin.shape())
71 z = Signal(self.z0.shape())
72 dx = Signal(self.sin.shape())
73 dy = Signal(self.sin.shape())
74 dz = Signal(self.z0.shape())
75 i = Signal(range(self.iterations))
76 state = Signal(CordicState, reset=CordicState.WAITING)
77
78 m.submodules.anglerom = anglerom = \
79 CordicROM(self.fracbits, self.iterations)
80
81 comb += dx.eq(y >> i)
82 comb += dy.eq(x >> i)
83 comb += dz.eq(anglerom.data)
84 comb += self.cos.eq(x)
85 comb += self.sin.eq(y)
86 with m.If(state == CordicState.WAITING):
87 with m.If(self.start):
88 sync += x.eq(X0)
89 sync += y.eq(0)
90 sync += z.eq(self.z0)
91 sync += i.eq(0)
92 sync += self.ready.eq(0)
93 sync += state.eq(CordicState.RUNNING)
94 sync += anglerom.addr.eq(1)
95 with m.If(state == CordicState.RUNNING):
96 with m.If(z >= 0):
97 sync += x.eq(x - dx)
98 sync += y.eq(y + dy)
99 sync += z.eq(z - dz)
100 with m.Else():
101 sync += x.eq(x + dx)
102 sync += y.eq(y - dy)
103 sync += z.eq(z + dz)
104 with m.If(i == self.iterations - 1):
105 sync += state.eq(CordicState.WAITING)
106 sync += self.ready.eq(1)
107 with m.Else():
108 sync += i.eq(i+1)
109 sync += anglerom.addr.eq(i+2)
110 return m
111
112 def ports(self):
113 return [self.cos, self.sin, self.z0,
114 self.ready, self.start]
115
116 if __name__ == '__main__':
117 dut = CORDIC(8)
118 vl = rtlil.convert(dut, ports=dut.ports())
119 with open("cordic.il", "w") as f:
120 f.write(vl)
121