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