From 037fd0d2696c2e94ab598ace5d443ac0400fde68 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 21 Dec 2018 06:07:16 +0000 Subject: [PATCH] hdl.mem: add tests for all error conditions. --- nmigen/hdl/mem.py | 23 ++++++-- nmigen/test/test_hdl_cd.py | 2 +- nmigen/test/test_hdl_mem.py | 109 ++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 7 deletions(-) create mode 100644 nmigen/test/test_hdl_mem.py diff --git a/nmigen/hdl/mem.py b/nmigen/hdl/mem.py index b6aacb7..c8518db 100644 --- a/nmigen/hdl/mem.py +++ b/nmigen/hdl/mem.py @@ -28,16 +28,27 @@ class Memory: self.depth = depth self.init = None if init is None else list(init) - def read_port(self, domain="sync", synchronous=False, transparent=True): + if self.init is not None and len(self.init) > self.depth: + raise ValueError("Memory initialization value count exceed memory depth ({} > {})" + .format(len(self.init), self.depth)) + + def read_port(self, domain="sync", synchronous=True, transparent=True): + if not synchronous and not transparent: + raise ValueError("Read port cannot be simultaneously asynchronous and non-transparent") return ReadPort(self, domain, synchronous, transparent) def write_port(self, domain="sync", priority=0, granularity=None): if granularity is None: granularity = self.width - if not isinstance(granularity, int) or granularity < 0 or granularity > self.width: - raise TypeError("Write port granularity must be a non-negative integer not greater " - "than memory width, not '{!r}'" + if not isinstance(granularity, int) or granularity < 0: + raise TypeError("Write port granularity must be a non-negative integer, not '{!r}'" .format(granularity)) + if granularity > self.width: + raise ValueError("Write port granularity must not be greater than memory width " + "({} > {})" + .format(granularity, self.width)) + if self.width // granularity * granularity != self.width: + raise ValueError("Write port granularity must divide memory width evenly") return WritePort(self, domain, priority, granularity) @@ -50,7 +61,7 @@ class ReadPort: self.addr = Signal(max=memory.depth) self.data = Signal(memory.width) - if synchronous and transparent: + if synchronous and not transparent: self.en = Signal() else: self.en = Const(1) @@ -63,7 +74,7 @@ class ReadPort: p_CLK_ENABLE=self.synchronous, p_CLK_POLARITY=1, p_TRANSPARENT=self.transparent, - i_CLK=ClockSignal(self.domain), + i_CLK=ClockSignal(self.domain) if self.synchronous else Const(0), i_EN=self.en, i_ADDR=self.addr, o_DATA=self.data, diff --git a/nmigen/test/test_hdl_cd.py b/nmigen/test/test_hdl_cd.py index 8e7dcdf..43619f8 100644 --- a/nmigen/test/test_hdl_cd.py +++ b/nmigen/test/test_hdl_cd.py @@ -2,7 +2,7 @@ from ..hdl.cd import * from .tools import * -class ClockDomainCase(FHDLTestCase): +class ClockDomainTestCase(FHDLTestCase): def test_name(self): sync = ClockDomain() self.assertEqual(sync.name, "sync") diff --git a/nmigen/test/test_hdl_mem.py b/nmigen/test/test_hdl_mem.py new file mode 100644 index 0000000..22ad5e3 --- /dev/null +++ b/nmigen/test/test_hdl_mem.py @@ -0,0 +1,109 @@ +from ..hdl.ast import * +from ..hdl.mem import * +from .tools import * + + +class MemoryTestCase(FHDLTestCase): + def test_name(self): + m1 = Memory(width=8, depth=4) + self.assertEqual(m1.name, "m1") + m2 = [Memory(width=8, depth=4)][0] + self.assertEqual(m2.name, "$memory") + m3 = Memory(width=8, depth=4, name="foo") + self.assertEqual(m3.name, "foo") + + def test_geometry(self): + m = Memory(width=8, depth=4) + self.assertEqual(m.width, 8) + self.assertEqual(m.depth, 4) + + def test_geometry_wrong(self): + with self.assertRaises(TypeError, + msg="Memory width must be a non-negative integer, not '-1'"): + m = Memory(width=-1, depth=4) + with self.assertRaises(TypeError, + msg="Memory depth must be a non-negative integer, not '-1'"): + m = Memory(width=8, depth=-1) + + def test_init(self): + m = Memory(width=8, depth=4, init=range(4)) + self.assertEqual(m.init, [0, 1, 2, 3]) + + def test_init_wrong(self): + with self.assertRaises(ValueError, + msg="Memory initialization value count exceed memory depth (8 > 4)"): + m = Memory(width=8, depth=4, init=range(8)) + + def test_read_port_transparent(self): + mem = Memory(width=8, depth=4) + rdport = mem.read_port() + self.assertEqual(rdport.memory, mem) + self.assertEqual(rdport.domain, "sync") + self.assertEqual(rdport.synchronous, True) + self.assertEqual(rdport.transparent, True) + self.assertEqual(len(rdport.addr), 2) + self.assertEqual(len(rdport.data), 8) + self.assertEqual(len(rdport.en), 1) + self.assertIsInstance(rdport.en, Const) + self.assertEqual(rdport.en.value, 1) + + def test_read_port_non_transparent(self): + mem = Memory(width=8, depth=4) + rdport = mem.read_port(transparent=False) + self.assertEqual(rdport.memory, mem) + self.assertEqual(rdport.domain, "sync") + self.assertEqual(rdport.synchronous, True) + self.assertEqual(rdport.transparent, False) + self.assertEqual(len(rdport.en), 1) + self.assertIsInstance(rdport.en, Signal) + + def test_read_port_asynchronous(self): + mem = Memory(width=8, depth=4) + rdport = mem.read_port(synchronous=False) + self.assertEqual(rdport.memory, mem) + self.assertEqual(rdport.domain, "sync") + self.assertEqual(rdport.synchronous, False) + self.assertEqual(rdport.transparent, True) + self.assertEqual(len(rdport.en), 1) + self.assertIsInstance(rdport.en, Const) + self.assertEqual(rdport.en.value, 1) + + def test_read_port_wrong(self): + mem = Memory(width=8, depth=4) + with self.assertRaises(ValueError, + msg="Read port cannot be simultaneously asynchronous and non-transparent"): + mem.read_port(synchronous=False, transparent=False) + + def test_write_port(self): + mem = Memory(width=8, depth=4) + wrport = mem.write_port() + self.assertEqual(wrport.memory, mem) + self.assertEqual(wrport.domain, "sync") + self.assertEqual(wrport.priority, 0) + self.assertEqual(wrport.granularity, 8) + self.assertEqual(len(wrport.addr), 2) + self.assertEqual(len(wrport.data), 8) + self.assertEqual(len(wrport.en), 1) + + def test_write_port_granularity(self): + mem = Memory(width=8, depth=4) + wrport = mem.write_port(granularity=2) + self.assertEqual(wrport.memory, mem) + self.assertEqual(wrport.domain, "sync") + self.assertEqual(wrport.priority, 0) + self.assertEqual(wrport.granularity, 2) + self.assertEqual(len(wrport.addr), 2) + self.assertEqual(len(wrport.data), 8) + self.assertEqual(len(wrport.en), 4) + + def test_write_port_granularity_wrong(self): + mem = Memory(width=8, depth=4) + with self.assertRaises(TypeError, + msg="Write port granularity must be a non-negative integer, not '-1'"): + mem.write_port(granularity=-1) + with self.assertRaises(ValueError, + msg="Write port granularity must not be greater than memory width (10 > 8)"): + mem.write_port(granularity=10) + with self.assertRaises(ValueError, + msg="Write port granularity must divide memory width evenly"): + mem.write_port(granularity=3) -- 2.30.2