1 # nmigen: UnusedElaboratable=no
5 from nmigen_soc
.memory
import MemoryMap
7 from litedram
.modules
import SDRAMModule
9 from ..cores
import litedram
12 class DummyConfig(litedram
.Config
):
16 class ConfigTestCase(unittest
.TestCase
):
17 def test_simple(self
):
20 module_name
= "MT41K256M16",
23 input_clk_freq
= int(100e6
),
24 user_clk_freq
= int(70e6
),
25 input_domain
= "input",
31 self
.assertEqual(cfg
.memtype
, "DDR3")
32 self
.assertEqual(cfg
.module_name
, "MT41K256M16")
33 self
.assertEqual(cfg
.module_bytes
, 2)
34 self
.assertEqual(cfg
.module_ranks
, 1)
35 self
.assertEqual(cfg
.phy_name
, "dummy")
36 self
.assertEqual(cfg
.input_clk_freq
, int(100e6
))
37 self
.assertEqual(cfg
.user_clk_freq
, int(70e6
))
38 self
.assertEqual(cfg
.input_domain
, "input")
39 self
.assertEqual(cfg
.user_domain
, "user")
40 self
.assertEqual(cfg
.user_data_width
, 32)
41 self
.assertEqual(cfg
.cmd_buffer_depth
, 8)
42 self
.assertEqual(cfg
.csr_data_width
, 32)
44 def test_get_module(self
):
47 module_name
= "MT41K256M16",
50 input_clk_freq
= int(100e6
),
51 user_clk_freq
= int(70e6
),
53 module
= cfg
.get_module()
54 self
.assertIsInstance(module
, SDRAMModule
)
56 def test_wrong_memtype(self
):
57 with self
.assertRaisesRegex(ValueError,
58 r
"Unsupported DRAM type, must be one of \"DDR2
\", \"DDR3
\" or \"DDR4
\", "
62 module_name = "MT41K256M16
",
65 input_clk_freq = int(100e6),
66 user_clk_freq = int(70e6),
69 def test_wrong_module_name(self):
70 with self.assertRaisesRegex(ValueError,
71 r"Module name must be a string
, not 42"):
77 input_clk_freq = int(100e6),
78 user_clk_freq = int(70e6),
81 def test_wrong_module_bytes(self):
82 with self.assertRaisesRegex(ValueError,
83 r"Number of byte groups must be a positive integer
, not 'foo'"):
86 module_name = "MT41K256M16
",
89 input_clk_freq = int(100e6),
90 user_clk_freq = int(70e6),
93 def test_wrong_module_ranks(self):
94 with self.assertRaisesRegex(ValueError,
95 r"Number of ranks must be a positive integer
, not 'foo'"):
98 module_name = "MT41K256M16
",
100 module_ranks = "foo
",
101 input_clk_freq = int(100e6),
102 user_clk_freq = int(70e6),
105 def test_wrong_input_clk_freq(self):
106 with self.assertRaisesRegex(ValueError,
107 r"Input clock frequency must be a positive integer
, not -1"):
110 module_name = "MT41K256M16
",
114 user_clk_freq = int(70e6),
117 def test_wrong_user_clk_freq(self):
118 with self.assertRaisesRegex(ValueError,
119 r"User clock frequency must be a positive integer
, not -1"):
122 module_name = "MT41K256M16
",
125 input_clk_freq = int(100e6),
129 def test_wrong_input_domain(self):
130 with self.assertRaisesRegex(ValueError,
131 r"Input domain name must be a string
, not 42"):
134 module_name = "MT41K256M16
",
137 input_clk_freq = int(100e6),
138 user_clk_freq = int(70e6),
142 def test_wrong_user_domain(self):
143 with self.assertRaisesRegex(ValueError,
144 r"User domain name must be a string
, not 42"):
147 module_name = "MT41K256M16
",
150 input_clk_freq = int(100e6),
151 user_clk_freq = int(70e6),
155 def test_wrong_user_data_width(self):
156 with self.assertRaisesRegex(ValueError,
157 r"User port data width must be one of
8, 16, 32, 64 or 128, not 42"):
160 module_name = "MT41K256M16
",
163 input_clk_freq = int(100e6),
164 user_clk_freq = int(70e6),
165 user_data_width = 42,
168 def test_wrong_cmd_buffer_depth(self):
169 with self.assertRaisesRegex(ValueError,
170 r"Command
buffer depth must be a positive integer
, not 'foo'"):
173 module_name = "MT41K256M16
",
176 input_clk_freq = int(100e6),
177 user_clk_freq = int(70e6),
178 cmd_buffer_depth = "foo
",
181 def test_wrong_csr_data_width(self):
182 with self.assertRaisesRegex(ValueError,
183 r"CSR data width must be one of
8, 16, 32, or 64, not 42"):
186 module_name = "MT41K256M16
",
189 input_clk_freq = int(100e6),
190 user_clk_freq = int(70e6),
195 class ECP5ConfigTestCase(unittest.TestCase):
196 def test_simple(self):
197 cfg = litedram.ECP5Config(
199 module_name = "MT41K256M16
",
202 input_clk_freq = int(100e6),
203 user_clk_freq = int(70e6),
204 init_clk_freq = int(25e6),
206 self.assertEqual(cfg.init_clk_freq, int(25e6))
207 self.assertEqual(cfg.phy_name, "ECP5DDRPHY
")
209 def test_wrong_init_clk_freq(self):
210 with self.assertRaisesRegex(ValueError,
211 r"Init clock frequency must be a positive integer
, not -1"):
212 cfg = litedram.ECP5Config(
214 module_name = "MT41K256M16
",
217 input_clk_freq = int(100e6),
218 user_clk_freq = int(70e6),
223 class Artix7ConfigTestCase(unittest.TestCase):
224 def test_simple(self):
225 cfg = litedram.Artix7Config(
229 module_name = "MT41K128M16
",
235 input_clk_freq = int(100e6),
236 user_clk_freq = int(100e6),
237 iodelay_clk_freq = int(200e6),
239 self.assertEqual(cfg.speedgrade, "-1")
240 self.assertEqual(cfg.cmd_latency, 0)
241 self.assertEqual(cfg.rtt_nom, 60)
242 self.assertEqual(cfg.rtt_wr, 60)
243 self.assertEqual(cfg.ron, 34)
244 self.assertEqual(cfg.iodelay_clk_freq, int(200e6))
245 self.assertEqual(cfg.phy_name, "A7DDRPHY
")
247 def test_wrong_speedgrade(self):
248 with self.assertRaisesRegex(ValueError,
249 r"Speed grade must be one of
'-1', '-2', '-2L', '-2G', '-3', "
251 cfg = litedram.Artix7Config(
255 module_name = "MT41K128M16
",
261 input_clk_freq = int(100e6),
262 user_clk_freq = int(100e6),
263 iodelay_clk_freq = int(200e6),
266 def test_wrong_cmd_latency(self):
267 with self.assertRaisesRegex(ValueError,
268 r"Command latency must be a non
-negative integer
, not -42"):
269 cfg = litedram.Artix7Config(
273 module_name = "MT41K128M16
",
279 input_clk_freq = int(100e6),
280 user_clk_freq = int(100e6),
281 iodelay_clk_freq = int(200e6),
284 def test_wrong_rtt_nom(self):
285 with self.assertRaisesRegex(ValueError,
286 r"Nominal termination impedance must be a non
-negative integer
, not -42"):
287 cfg = litedram.Artix7Config(
291 module_name = "MT41K128M16
",
297 input_clk_freq = int(100e6),
298 user_clk_freq = int(100e6),
299 iodelay_clk_freq = int(200e6),
302 def test_wrong_rtt_wr(self):
303 with self.assertRaisesRegex(ValueError,
304 r"Write termination impedance must be a non
-negative integer
, not -42"):
305 cfg = litedram.Artix7Config(
309 module_name = "MT41K128M16
",
315 input_clk_freq = int(100e6),
316 user_clk_freq = int(100e6),
317 iodelay_clk_freq = int(200e6),
320 def test_wrong_ron(self):
321 with self.assertRaisesRegex(ValueError,
322 r"Output driver impedance must be a non
-negative integer
, not -42"):
323 cfg = litedram.Artix7Config(
327 module_name = "MT41K128M16
",
333 input_clk_freq = int(100e6),
334 user_clk_freq = int(100e6),
335 iodelay_clk_freq = int(200e6),
338 def test_wrong_iodelay_clk_freq(self):
339 with self.assertRaisesRegex(ValueError,
340 r"IODELAY clock frequency must be a positive integer
, not -1"):
341 cfg = litedram.Artix7Config(
345 module_name = "MT41K128M16
",
351 input_clk_freq = int(100e6),
352 user_clk_freq = int(100e6),
353 iodelay_clk_freq = -1,
357 class NativePortTestCase(unittest.TestCase):
358 def test_simple(self):
359 port = litedram.NativePort(addr_width=10, data_width=32)
360 self.assertEqual(port.addr_width, 10)
361 self.assertEqual(port.data_width, 32)
362 self.assertEqual(port.granularity, 8)
363 self.assertEqual(len(port.cmd.addr), 10)
364 self.assertEqual(len(port.w.data), 32)
365 self.assertEqual(len(port.w.we), 4)
366 self.assertEqual(len(port.r.data), 32)
370 "(rec port__cmd valid ready last we addr
) "
371 "(rec port__w valid ready data we
) "
372 "(rec port__r valid ready data
))"
375 def test_memory_map(self):
376 port = litedram.NativePort(addr_width=10, data_width=32)
377 port_map = MemoryMap(addr_width=12, data_width=8)
378 port.memory_map = port_map
379 self.assertIs(port.memory_map, port_map)
381 def test_wrong_memory_map(self):
382 port = litedram.NativePort(addr_width=10, data_width=32)
383 with self.assertRaisesRegex(TypeError,
384 r"Memory
map must be an instance of MemoryMap
, not 'foo'"):
385 port.memory_map = "foo
"
387 def test_wrong_memory_map_data_width(self):
388 port = litedram.NativePort(addr_width=10, data_width=32)
389 port_map = MemoryMap(addr_width=11, data_width=16)
390 with self.assertRaisesRegex(ValueError,
391 r"Memory
map has data width
16, which
is not the same
as native port granularity
"
393 port.memory_map = port_map
395 def test_wrong_memory_map_addr_width(self):
396 port = litedram.NativePort(addr_width=10, data_width=32)
397 port_map = MemoryMap(addr_width=11, data_width=8)
398 with self.assertRaisesRegex(ValueError,
399 r"Memory
map has address width
11, which
is not the same
as native port address
"
400 r"width
12 \
(10 address bits \
+ 2 granularity bits\
)"):
401 port.memory_map = port_map
404 class CoreTestCase(unittest.TestCase):
405 def __init__(self, *args, **kwargs):
406 super().__init__(*args, **kwargs)
407 self._cfg = litedram.ECP5Config(
409 module_name = "MT41K256M16
",
412 input_clk_freq = int(100e6),
413 user_clk_freq = int(70e6),
414 init_clk_freq = int(25e6),
418 litedram.Core.clear_namespace()
421 litedram.Core.clear_namespace()
423 def test_simple(self):
424 core = litedram.Core(self._cfg)
425 self.assertIs(core.config, self._cfg)
426 self.assertEqual(core.name, "core
")
427 self.assertEqual(core.size, 512 * 1024 * 1024)
428 self.assertEqual(core.user_port.addr_width, 25)
429 self.assertEqual(core.user_port.data_width, 128)
430 self.assertEqual(core.user_port.memory_map.addr_width, 29)
431 self.assertEqual(core.user_port.memory_map.data_width, 8)
433 def test_name_force(self):
434 core_1 = litedram.Core(self._cfg, name="core
")
435 core_2 = litedram.Core(self._cfg, name="core
", name_force=True)
436 self.assertEqual(core_1.name, "core
")
437 self.assertEqual(core_2.name, "core
")
439 def test_ctrl_bus_not_ready(self):
440 core = litedram.Core(self._cfg)
441 with self.assertRaisesRegex(AttributeError,
442 r"Core
.build\
(do_build
=True\
) must be called before accessing Core\
.ctrl_bus
"):
445 def test_wrong_config(self):
446 with self.assertRaisesRegex(TypeError,
447 r"Config must be an instance of litedram\
.Config
, not 'foo'"):
448 core = litedram.Core("foo
")
450 def test_wrong_name(self):
451 with self.assertRaisesRegex(TypeError,
452 r"Name must be a string
, not 42"):
453 core = litedram.Core(self._cfg, name=42)
455 def test_wrong_name_collision(self):
456 core_1 = litedram.Core(self._cfg, name="core
")
457 with self.assertRaisesRegex(ValueError,
458 r"Name
'core' has already been used
for a previous litedram\
.Core instance\
. "
459 r"Building this instance may overwrite previous build products
. Passing
"
460 r"`name_force
=True` will disable this check
."):
461 core_2 = litedram.Core(self._cfg, name="core
")