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
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
8 from enum
import Enum
, unique
9 from ieee754
.fpcommon
.fpbase
import FPNumBaseRecord
, FPNumDecode
13 class CordicState(Enum
):
19 class CordicROM(Elaboratable
):
20 def __init__(self
, fracbits
, iterations
):
21 self
.fracbits
= fracbits
22 self
.iterations
= iterations
25 self
.addr
= Signal(range(iterations
))
26 self
.data
= Signal(range(-M
, M
-1))
28 angles
= [int(round(M
*math
.atan(2**(-i
))))
29 for i
in range(self
.iterations
)]
31 self
.mem
= Memory(width
=self
.data
.width
,
32 depth
=self
.iterations
,
35 def elaborate(self
, platform
):
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
)
43 class CORDIC(Elaboratable
):
44 def __init__(self
, width
):
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))
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)
58 self
.start
= Signal(reset_less
=True)
59 # cordic done/ready for input
60 self
.ready
= Signal(reset
=True)
62 self
.width
= self
.z0
.width
63 self
.iterations
= self
.width
- 1
65 def elaborate(self
, platform
):
70 m
.submodules
.z_in
= z_in
= FPNumDecode(None, self
.z_record
)
71 comb
+= z_in
.v
.eq(self
.z0
)
73 z_fixed
= Signal(range(-self
.ZMAX
, self
.ZMAX
-1),
76 # Calculate initial amplitude?
78 for i
in range(self
.iterations
):
79 An
*= math
.sqrt(1 + 2**(-2*i
))
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
)
91 m
.submodules
.anglerom
= anglerom
= \
92 CordicROM(self
.fracbits
, self
.iterations
)
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
):
106 sync
+= z
.eq(z_fixed
)
108 sync
+= state
.eq(CordicState
.RUNNING
)
109 sync
+= anglerom
.addr
.eq(1)
110 with m
.If(state
== CordicState
.RUNNING
):
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)
125 sync
+= anglerom
.addr
.eq(i
+2)
129 lst
= [self
.cos
, self
.sin
,
130 self
.ready
, self
.start
]
135 if __name__
== '__main__':
137 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
138 with
open("cordic.il", "w") as f
: