cores.pll: add PLL generators for Lattice ECP5 and Xilinx 7 Series.
[lambdasoc.git] / lambdasoc / test / test_cores_pll_lattice_ecp5.py
1 # nmigen: UnusedElaboratable=no
2
3 import unittest
4 from nmigen import *
5
6 from ..cores.pll.lattice_ecp5 import PLL_LatticeECP5
7
8
9 class PLL_LatticeECP5__ParametersTestCase(unittest.TestCase):
10 def test_simple(self):
11 params1 = PLL_LatticeECP5.Parameters(
12 i_domain = "foo",
13 i_freq = 100e6,
14 o_domain = "bar",
15 o_freq = 50e6,
16 )
17 self.assertEqual(params1.i_domain, "foo")
18 self.assertEqual(params1.i_freq, 100e6)
19 self.assertEqual(params1.i_reset_less, True)
20 self.assertEqual(params1.o_domain, "bar")
21 self.assertEqual(params1.o_freq, 50e6)
22 self.assertEqual(params1.fb_internal, False)
23
24 params2 = PLL_LatticeECP5.Parameters(
25 i_domain = "baz",
26 i_freq = int(12e6),
27 i_reset_less = False,
28 o_domain = "qux",
29 o_freq = int(48e6),
30 fb_internal = True,
31 )
32 self.assertEqual(params2.i_domain, "baz")
33 self.assertEqual(params2.i_freq, 12e6)
34 self.assertEqual(params2.i_reset_less, False)
35 self.assertEqual(params2.o_domain, "qux")
36 self.assertEqual(params2.o_freq, 48e6)
37 self.assertEqual(params2.fb_internal, True)
38
39 def test_wrong_i_domain(self):
40 with self.assertRaisesRegex(TypeError,
41 r"Input domain must be a string, not 1"):
42 params = PLL_LatticeECP5.Parameters(
43 i_domain = 1,
44 i_freq = 100e6,
45 o_domain = "bar",
46 o_freq = 50e6,
47 )
48
49 def test_wrong_i_freq_type(self):
50 with self.assertRaisesRegex(TypeError,
51 r"Input frequency must be an integer or a float, not 'baz'"):
52 params = PLL_LatticeECP5.Parameters(
53 i_domain = "foo",
54 i_freq = "baz",
55 o_domain = "bar",
56 o_freq = 50e6,
57 )
58
59 def test_wrong_i_freq_range(self):
60 with self.assertRaisesRegex(ValueError,
61 r"Input frequency must be between 8 and 400 MHz, not 420.0 MHz"):
62 params = PLL_LatticeECP5.Parameters(
63 i_domain = "foo",
64 i_freq = 420e6,
65 o_domain = "bar",
66 o_freq = 50e6,
67 )
68
69 def test_wrong_o_domain(self):
70 with self.assertRaisesRegex(TypeError,
71 r"Output domain must be a string, not 1"):
72 params = PLL_LatticeECP5.Parameters(
73 i_domain = "foo",
74 i_freq = 100e6,
75 o_domain = 1,
76 o_freq = 50e6,
77 )
78
79 def test_wrong_o_freq_type(self):
80 with self.assertRaisesRegex(TypeError,
81 r"Output frequency must be an integer or a float, not 'baz'"):
82 params = PLL_LatticeECP5.Parameters(
83 i_domain = "foo",
84 i_freq = 50e6,
85 o_domain = "bar",
86 o_freq = "baz",
87 )
88
89 def test_wrong_o_freq_range(self):
90 with self.assertRaisesRegex(ValueError,
91 r"Output frequency must be between 10 and 400 MHz, not 420.0 MHz"):
92 params = PLL_LatticeECP5.Parameters(
93 i_domain = "foo",
94 i_freq = 100e6,
95 o_domain = "bar",
96 o_freq = 420e6,
97 )
98
99 def test_add_secondary_output_wrong_domain(self):
100 params = PLL_LatticeECP5.Parameters(
101 i_domain = "foo",
102 i_freq = 100e6,
103 o_domain = "bar",
104 o_freq = 50e6,
105 )
106 with self.assertRaisesRegex(TypeError,
107 r"Output domain must be a string, not 1"):
108 params.add_secondary_output(domain=1, freq=10e6)
109
110 def test_add_secondary_output_wrong_freq_type(self):
111 params = PLL_LatticeECP5.Parameters(
112 i_domain = "foo",
113 i_freq = 100e6,
114 o_domain = "bar",
115 o_freq = 50e6,
116 )
117 with self.assertRaisesRegex(TypeError,
118 r"Output frequency must be an integer or a float, not 'a'"):
119 params.add_secondary_output(domain="baz", freq="a")
120
121 def test_add_secondary_output_wrong_freq_range(self):
122 params = PLL_LatticeECP5.Parameters(
123 i_domain = "foo",
124 i_freq = 100e6,
125 o_domain = "bar",
126 o_freq = 50e6,
127 )
128 with self.assertRaisesRegex(ValueError,
129 r"Output frequency must be between 10 and 400 MHz, not 8.0 MHz"):
130 params.add_secondary_output(domain="baz", freq=8e6)
131
132 def test_add_secondary_output_wrong_phase_type(self):
133 params = PLL_LatticeECP5.Parameters(
134 i_domain = "foo",
135 i_freq = 100e6,
136 o_domain = "bar",
137 o_freq = 50e6,
138 )
139 with self.assertRaisesRegex(TypeError,
140 r"Output phase must be an integer or a float, not 'a'"):
141 params.add_secondary_output(domain="baz", freq=10e6, phase="a")
142
143 def test_add_secondary_output_wrong_phase_range(self):
144 params = PLL_LatticeECP5.Parameters(
145 i_domain = "foo",
146 i_freq = 100e6,
147 o_domain = "bar",
148 o_freq = 50e6,
149 )
150 with self.assertRaisesRegex(ValueError,
151 r"Output phase must be between 0 and 360 degrees, not -1"):
152 params.add_secondary_output(domain="baz", freq=10e6, phase=-1)
153
154 def test_add_secondary_output_exceeded(self):
155 params = PLL_LatticeECP5.Parameters(
156 i_domain = "foo",
157 i_freq = 100e6,
158 o_domain = "bar",
159 o_freq = 50e6,
160 )
161 params.add_secondary_output(domain="a", freq=10e6)
162 params.add_secondary_output(domain="b", freq=10e6)
163 params.add_secondary_output(domain="c", freq=10e6)
164 with self.assertRaisesRegex(ValueError,
165 r"This PLL can drive at most 3 secondary outputs"):
166 params.add_secondary_output(domain="d", freq=10e6)
167
168 def test_add_secondary_output_same_domain(self):
169 params = PLL_LatticeECP5.Parameters(
170 i_domain = "foo",
171 i_freq = 100e6,
172 o_domain = "bar",
173 o_freq = 50e6,
174 )
175 params.add_secondary_output(domain="a", freq=10e6)
176 with self.assertRaisesRegex(ValueError,
177 r"Output domain 'a' has already been added"):
178 params.add_secondary_output(domain="a", freq=10e6)
179
180 def test_compute_primary(self):
181 def result(i_freq, o_freq):
182 params = PLL_LatticeECP5.Parameters(
183 i_domain = "i",
184 i_freq = i_freq,
185 o_domain = "o",
186 o_freq = o_freq,
187 )
188 params.compute()
189 return (params.i_div, params.fb_div, params.op.div)
190
191 vectors = [
192 # Values are taken from ecppll in prjtrellis.
193 # i_freq, o_freq, i_div, fb_div, op_div
194 ( 12e6, 48e6, 1, 4, 12),
195 ( 12e6, 60e6, 1, 5, 10),
196 ( 20e6, 30e6, 2, 3, 20),
197 ( 45e6, 30e6, 3, 2, 20),
198 ( 100e6, 400e6, 1, 4, 1),
199 ( 200e6, 400e6, 1, 2, 1),
200 ( 50e6, 400e6, 1, 8, 1),
201 ( 70e6, 40e6, 7, 4, 15),
202 ( 12e6, 36e6, 1, 3, 17),
203 ( 12e6, 96e6, 1, 8, 6),
204 ( 90e6, 40e6, 9, 4, 15),
205 ( 90e6, 50e6, 9, 5, 12),
206 ( 43e6, 86e6, 1, 2, 7),
207 ]
208
209 self.assertEqual(
210 [(i_freq, o_freq, *result(i_freq, o_freq)) for i_freq, o_freq, *_ in vectors],
211 vectors
212 )
213
214 # TODO
215 # def test_compute_secondary(self):
216 # pass
217
218 def test_add_secondary_output_frozen(self):
219 params = PLL_LatticeECP5.Parameters(
220 i_domain = "foo",
221 i_freq = 100e6,
222 o_domain = "bar",
223 o_freq = 50e6,
224 )
225 params.compute()
226 with self.assertRaisesRegex(ValueError,
227 r"PLL parameters have already been computed. Other outputs cannot be added"):
228 params.add_secondary_output(domain="a", freq=10e6)