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