1 # nmigen: UnusedElaboratable=no
5 from nmigen_soc
.memory
import MemoryMap
6 from nmigen_boards
.ecpix5
import ECPIX585Platform
8 from litedram
.modules
import SDRAMModule
10 from ..cores
import litedram
13 class DummyConfig(litedram
.Config
):
17 class ConfigTestCase(unittest
.TestCase
):
18 def test_simple(self
):
21 module_name
= "MT41K256M16",
24 input_clk_freq
= int(100e6
),
25 user_clk_freq
= int(70e6
),
26 input_domain
= "input",
32 self
.assertEqual(cfg
.memtype
, "DDR3")
33 self
.assertEqual(cfg
.module_name
, "MT41K256M16")
34 self
.assertEqual(cfg
.module_bytes
, 2)
35 self
.assertEqual(cfg
.module_ranks
, 1)
36 self
.assertEqual(cfg
.phy_name
, "dummy")
37 self
.assertEqual(cfg
.input_clk_freq
, int(100e6
))
38 self
.assertEqual(cfg
.user_clk_freq
, int(70e6
))
39 self
.assertEqual(cfg
.input_domain
, "input")
40 self
.assertEqual(cfg
.user_domain
, "user")
41 self
.assertEqual(cfg
.user_data_width
, 32)
42 self
.assertEqual(cfg
.cmd_buffer_depth
, 8)
43 self
.assertEqual(cfg
.csr_data_width
, 32)
45 def test_get_module(self
):
48 module_name
= "MT41K256M16",
51 input_clk_freq
= int(100e6
),
52 user_clk_freq
= int(70e6
),
54 module
= cfg
.get_module()
55 self
.assertIsInstance(module
, SDRAMModule
)
57 def test_wrong_memtype(self
):
58 with self
.assertRaisesRegex(ValueError,
59 r
"Unsupported DRAM type, must be one of \"SDR
\", \"DDR
\", \"LPDDR
\", \"DDR2
\", "
60 r"\"DDR3
\" or \"DDR4
\", not 'foo'"):
63 module_name = "MT41K256M16
",
66 input_clk_freq = int(100e6),
67 user_clk_freq = int(70e6),
70 def test_wrong_module_name(self):
71 with self.assertRaisesRegex(ValueError,
72 r"Module name must be a string
, not 42"):
78 input_clk_freq = int(100e6),
79 user_clk_freq = int(70e6),
82 def test_wrong_module_bytes(self):
83 with self.assertRaisesRegex(ValueError,
84 r"Number of byte groups must be a positive integer
, not 'foo'"):
87 module_name = "MT41K256M16
",
90 input_clk_freq = int(100e6),
91 user_clk_freq = int(70e6),
94 def test_wrong_module_ranks(self):
95 with self.assertRaisesRegex(ValueError,
96 r"Number of ranks must be a positive integer
, not 'foo'"):
99 module_name = "MT41K256M16
",
101 module_ranks = "foo
",
102 input_clk_freq = int(100e6),
103 user_clk_freq = int(70e6),
106 def test_wrong_input_clk_freq(self):
107 with self.assertRaisesRegex(ValueError,
108 r"Input clock frequency must be a positive integer
, not -1"):
111 module_name = "MT41K256M16
",
115 user_clk_freq = int(70e6),
118 def test_wrong_user_clk_freq(self):
119 with self.assertRaisesRegex(ValueError,
120 r"User clock frequency must be a positive integer
, not -1"):
123 module_name = "MT41K256M16
",
126 input_clk_freq = int(100e6),
130 def test_wrong_input_domain(self):
131 with self.assertRaisesRegex(ValueError,
132 r"Input domain name must be a string
, not 42"):
135 module_name = "MT41K256M16
",
138 input_clk_freq = int(100e6),
139 user_clk_freq = int(70e6),
143 def test_wrong_user_domain(self):
144 with self.assertRaisesRegex(ValueError,
145 r"User domain name must be a string
, not 42"):
148 module_name = "MT41K256M16
",
151 input_clk_freq = int(100e6),
152 user_clk_freq = int(70e6),
156 def test_wrong_user_data_width(self):
157 with self.assertRaisesRegex(ValueError,
158 r"User port data width must be one of
8, 16, 32, 64 or 128, not 42"):
161 module_name = "MT41K256M16
",
164 input_clk_freq = int(100e6),
165 user_clk_freq = int(70e6),
166 user_data_width = 42,
169 def test_wrong_cmd_buffer_depth(self):
170 with self.assertRaisesRegex(ValueError,
171 r"Command
buffer depth must be a positive integer
, not 'foo'"):
174 module_name = "MT41K256M16
",
177 input_clk_freq = int(100e6),
178 user_clk_freq = int(70e6),
179 cmd_buffer_depth = "foo
",
182 def test_wrong_csr_data_width(self):
183 with self.assertRaisesRegex(ValueError,
184 r"CSR data width must be one of
8, 16, 32, or 64, not 42"):
187 module_name = "MT41K256M16
",
190 input_clk_freq = int(100e6),
191 user_clk_freq = int(70e6),
196 class ECP5ConfigTestCase(unittest.TestCase):
197 def test_simple(self):
198 cfg = litedram.ECP5Config(
200 module_name = "MT41K256M16
",
203 input_clk_freq = int(100e6),
204 user_clk_freq = int(70e6),
205 init_clk_freq = int(25e6),
207 self.assertEqual(cfg.init_clk_freq, int(25e6))
208 self.assertEqual(cfg.phy_name, "ECP5DDRPHY
")
210 def test_wrong_init_clk_freq(self):
211 with self.assertRaisesRegex(ValueError,
212 r"Init clock frequency must be a positive integer
, not -1"):
213 cfg = litedram.ECP5Config(
215 module_name = "MT41K256M16
",
218 input_clk_freq = int(100e6),
219 user_clk_freq = int(70e6),
224 class Artix7ConfigTestCase(unittest.TestCase):
225 def test_simple(self):
226 cfg = litedram.Artix7Config(
230 module_name = "MT41K128M16
",
236 input_clk_freq = int(100e6),
237 user_clk_freq = int(100e6),
238 iodelay_clk_freq = int(200e6),
240 self.assertEqual(cfg.speedgrade, "-1")
241 self.assertEqual(cfg.cmd_latency, 0)
242 self.assertEqual(cfg.rtt_nom, 60)
243 self.assertEqual(cfg.rtt_wr, 60)
244 self.assertEqual(cfg.ron, 34)
245 self.assertEqual(cfg.iodelay_clk_freq, int(200e6))
246 self.assertEqual(cfg.phy_name, "A7DDRPHY
")
248 def test_wrong_speedgrade(self):
249 with self.assertRaisesRegex(ValueError,
250 r"Speed grade must be one of
'-1', '-2', '-2L', '-2G', '-3', "
252 cfg = litedram.Artix7Config(
256 module_name = "MT41K128M16
",
262 input_clk_freq = int(100e6),
263 user_clk_freq = int(100e6),
264 iodelay_clk_freq = int(200e6),
267 def test_wrong_cmd_latency(self):
268 with self.assertRaisesRegex(ValueError,
269 r"Command latency must be a non
-negative integer
, not -42"):
270 cfg = litedram.Artix7Config(
274 module_name = "MT41K128M16
",
280 input_clk_freq = int(100e6),
281 user_clk_freq = int(100e6),
282 iodelay_clk_freq = int(200e6),
285 def test_wrong_rtt_nom(self):
286 with self.assertRaisesRegex(ValueError,
287 r"Nominal termination impedance must be a non
-negative integer
, not -42"):
288 cfg = litedram.Artix7Config(
292 module_name = "MT41K128M16
",
298 input_clk_freq = int(100e6),
299 user_clk_freq = int(100e6),
300 iodelay_clk_freq = int(200e6),
303 def test_wrong_rtt_wr(self):
304 with self.assertRaisesRegex(ValueError,
305 r"Write termination impedance must be a non
-negative integer
, not -42"):
306 cfg = litedram.Artix7Config(
310 module_name = "MT41K128M16
",
316 input_clk_freq = int(100e6),
317 user_clk_freq = int(100e6),
318 iodelay_clk_freq = int(200e6),
321 def test_wrong_ron(self):
322 with self.assertRaisesRegex(ValueError,
323 r"Output driver impedance must be a non
-negative integer
, not -42"):
324 cfg = litedram.Artix7Config(
328 module_name = "MT41K128M16
",
334 input_clk_freq = int(100e6),
335 user_clk_freq = int(100e6),
336 iodelay_clk_freq = int(200e6),
339 def test_wrong_iodelay_clk_freq(self):
340 with self.assertRaisesRegex(ValueError,
341 r"IODELAY clock frequency must be a positive integer
, not -1"):
342 cfg = litedram.Artix7Config(
346 module_name = "MT41K128M16
",
352 input_clk_freq = int(100e6),
353 user_clk_freq = int(100e6),
354 iodelay_clk_freq = -1,
358 class NativePortTestCase(unittest.TestCase):
359 def test_simple(self):
360 port = litedram.NativePort(addr_width=10, data_width=32)
361 self.assertEqual(port.addr_width, 10)
362 self.assertEqual(port.data_width, 32)
363 self.assertEqual(port.granularity, 8)
364 self.assertEqual(len(port.cmd.addr), 10)
365 self.assertEqual(len(port.w.data), 32)
366 self.assertEqual(len(port.w.we), 4)
367 self.assertEqual(len(port.r.data), 32)
371 "(rec port__cmd valid ready last we addr
) "
372 "(rec port__w valid ready data we
) "
373 "(rec port__r valid ready data
))"
376 def test_memory_map(self):
377 port = litedram.NativePort(addr_width=10, data_width=32)
378 port_map = MemoryMap(addr_width=12, data_width=8)
379 port.memory_map = port_map
380 self.assertIs(port.memory_map, port_map)
382 def test_wrong_memory_map(self):
383 port = litedram.NativePort(addr_width=10, data_width=32)
384 with self.assertRaisesRegex(TypeError,
385 r"Memory
map must be an instance of MemoryMap
, not 'foo'"):
386 port.memory_map = "foo
"
388 def test_wrong_memory_map_data_width(self):
389 port = litedram.NativePort(addr_width=10, data_width=32)
390 port_map = MemoryMap(addr_width=11, data_width=16)
391 with self.assertRaisesRegex(ValueError,
392 r"Memory
map has data width
16, which
is not the same
as native port granularity
"
394 port.memory_map = port_map
396 def test_wrong_memory_map_addr_width(self):
397 port = litedram.NativePort(addr_width=10, data_width=32)
398 port_map = MemoryMap(addr_width=11, data_width=8)
399 with self.assertRaisesRegex(ValueError,
400 r"Memory
map has address width
11, which
is not the same
as native port address
"
401 r"width
12 \
(10 address bits \
+ 2 granularity bits\
)"):
402 port.memory_map = port_map
405 class CoreTestCase(unittest.TestCase):
406 def __init__(self, *args, **kwargs):
407 super().__init__(*args, **kwargs)
408 self._cfg = litedram.ECP5Config(
410 module_name = "MT41K256M16
",
413 input_clk_freq = int(100e6),
414 user_clk_freq = int(70e6),
415 init_clk_freq = int(25e6),
418 def test_simple(self):
419 core = litedram.Core(self._cfg)
420 self.assertIs(core.config, self._cfg)
421 self.assertEqual(core.name, "core
")
422 self.assertEqual(core.size, 512 * 1024 * 1024)
423 self.assertEqual(core.user_port.addr_width, 25)
424 self.assertEqual(core.user_port.data_width, 128)
425 self.assertEqual(core.user_port.memory_map.addr_width, 29)
426 self.assertEqual(core.user_port.memory_map.data_width, 8)
428 def test_ctrl_bus_not_ready(self):
429 core = litedram.Core(self._cfg)
430 with self.assertRaisesRegex(AttributeError,
431 r"Control bus memory
map has
not been populated
. Core
.build\
(do_build
=True\
) must
"
432 r"be called before accessing Core\
.ctrl_bus
"):
435 def test_wrong_config(self):
436 with self.assertRaisesRegex(TypeError,
437 r"Config must be an instance of litedram\
.Config
, not 'foo'"):
438 core = litedram.Core("foo
")
440 def test_wrong_name(self):
441 with self.assertRaisesRegex(TypeError,
442 r"Name must be a string
, not 42"):
443 core = litedram.Core(self._cfg, name=42)
446 class BuilderTestCase(unittest.TestCase):
447 def __init__(self, *args, **kwargs):
448 super().__init__(*args, **kwargs)
449 self._cfg = litedram.ECP5Config(
451 module_name = "MT41K256M16
",
454 input_clk_freq = int(100e6),
455 user_clk_freq = int(70e6),
456 init_clk_freq = int(25e6),
459 def test_prepare(self):
460 core = litedram.Core(self._cfg)
461 builder = litedram.Builder()
462 builder.prepare(core, ECPIX585Platform())
463 self.assertEqual(list(builder.namespace), ["core
"])
465 def test_prepare_name_conflict(self):
466 core = litedram.Core(self._cfg)
467 builder = litedram.Builder()
468 builder.prepare(core, ECPIX585Platform())
469 with self.assertRaisesRegex(ValueError,
470 r"LiteDRAM core name
'core' has already been used
for a previous build\
. Building
"
471 r"this instance may overwrite previous build products\
. Passing `name_force
=True`
"
472 r"will disable this check
"):
473 builder.prepare(core, ECPIX585Platform())
475 def test_prepare_name_force(self):
476 core = litedram.Core(self._cfg)
477 builder = litedram.Builder()
478 builder.prepare(core, ECPIX585Platform())
479 builder.prepare(core, ECPIX585Platform(), name_force=True)
481 def test_prepare_wrong_core(self):
482 builder = litedram.Builder()
483 with self.assertRaisesRegex(TypeError,
484 r"LiteDRAM core must be an instance of litedram
.Core
, not 'foo'"):
485 builder.prepare("foo
", ECPIX585Platform())
487 def test_prepare_wrong_platform(self):
488 core = litedram.Core(self._cfg)
489 builder = litedram.Builder()
490 with self.assertRaisesRegex(TypeError,
491 r"Target platform must be an instance of nmigen
.build
.plat
.Platform
, not 'foo'"):
492 builder.prepare(core, "foo
")