Skip to content

Commit b8b1e70

Browse files
committed
lib.memory: improve and regularize diagnostics.
1 parent 8d44ec5 commit b8b1e70

File tree

2 files changed

+52
-42
lines changed

2 files changed

+52
-42
lines changed

amaranth/lib/memory.py

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ class Signature(wiring.Signature):
294294

295295
def __init__(self, *, addr_width, shape):
296296
if not isinstance(addr_width, int) or addr_width < 0:
297-
raise TypeError(f"`addr_width` must be a non-negative int, not {addr_width!r}")
297+
raise TypeError(f"Address width must be a non-negative integer, not {addr_width!r}")
298298
self._addr_width = addr_width
299299
self._shape = shape
300300
super().__init__({
@@ -326,24 +326,27 @@ def __repr__(self):
326326

327327
def __init__(self, signature, *, memory, domain, transparent_for=(), path=None, src_loc_at=0):
328328
if not isinstance(signature, ReadPort.Signature):
329-
raise TypeError(f"Expected `ReadPort.Signature`, not {signature!r}")
329+
raise TypeError(f"Expected signature to be ReadPort.Signature, not {signature!r}")
330330
if memory is not None: # may be None if created via `Signature.create()`
331331
if not isinstance(memory, Memory):
332-
raise TypeError(f"Expected `Memory` or `None`, not {memory!r}")
333-
if signature.shape != memory.shape or Shape.cast(signature.shape) != Shape.cast(memory.shape):
334-
raise ValueError(f"Memory shape {memory.shape!r} doesn't match port shape {signature.shape!r}")
332+
raise TypeError(f"Expected memory to be Memory or None, not {memory!r}")
333+
if (signature.shape != memory.shape or
334+
Shape.cast(signature.shape) != Shape.cast(memory.shape)):
335+
raise ValueError(f"Memory shape {memory.shape!r} doesn't match "
336+
f"port shape {signature.shape!r}")
335337
if signature.addr_width != ceil_log2(memory.depth):
336-
raise ValueError(f"Memory address width {ceil_log2(memory.depth)!r} doesn't match port address width {signature.addr_width!r}")
338+
raise ValueError(f"Memory address width {ceil_log2(memory.depth)!r} doesn't match "
339+
f"port address width {signature.addr_width!r}")
337340
if not isinstance(domain, str):
338-
raise TypeError(f"Domain has to be a string, not {domain!r}")
341+
raise TypeError(f"Domain must be a string, not {domain!r}")
339342
transparent_for = tuple(transparent_for)
340343
for port in transparent_for:
341344
if not isinstance(port, WritePort):
342-
raise TypeError("`transparent_for` must contain only `WritePort` instances")
345+
raise TypeError("Transparency set must contain only WritePort instances")
343346
if memory is not None and port not in memory._write_ports:
344-
raise ValueError("Transparent write ports must belong to the same memory")
347+
raise ValueError("Ports in transparency set must belong to the same memory")
345348
if port.domain != domain:
346-
raise ValueError("Transparent write ports must belong to the same domain")
349+
raise ValueError("Ports in transparency set must belong to the same domain")
347350
self._signature = signature
348351
self._memory = memory
349352
self._domain = domain
@@ -420,24 +423,26 @@ class Signature(wiring.Signature):
420423

421424
def __init__(self, *, addr_width, shape, granularity=None):
422425
if not isinstance(addr_width, int) or addr_width < 0:
423-
raise TypeError(f"`addr_width` must be a non-negative int, not {addr_width!r}")
426+
raise TypeError(f"Address width must be a non-negative integer, not {addr_width!r}")
424427
self._addr_width = addr_width
425428
self._shape = shape
426429
self._granularity = granularity
427430
if granularity is None:
428431
en_width = 1
429432
elif not isinstance(granularity, int) or granularity < 0:
430-
raise TypeError(f"Granularity must be a non-negative int or None, not {granularity!r}")
433+
raise TypeError(f"Granularity must be a non-negative integer or None, "
434+
f"not {granularity!r}")
431435
elif not isinstance(shape, ShapeCastable):
432436
actual_shape = Shape.cast(shape)
433437
if actual_shape.signed:
434-
raise ValueError("Granularity cannot be specified with signed shape")
438+
raise ValueError("Granularity cannot be specified for a memory with "
439+
"a signed shape")
435440
elif actual_shape.width == 0:
436441
en_width = 0
437442
elif granularity == 0:
438443
raise ValueError("Granularity must be positive")
439444
elif actual_shape.width % granularity != 0:
440-
raise ValueError("Granularity must divide data width")
445+
raise ValueError("Granularity must evenly divide data width")
441446
else:
442447
en_width = actual_shape.width // granularity
443448
elif isinstance(shape, data.ArrayLayout):
@@ -446,11 +451,12 @@ def __init__(self, *, addr_width, shape, granularity=None):
446451
elif granularity == 0:
447452
raise ValueError("Granularity must be positive")
448453
elif shape.length % granularity != 0:
449-
raise ValueError("Granularity must divide data array length")
454+
raise ValueError("Granularity must evenly divide data array length")
450455
else:
451456
en_width = shape.length // granularity
452457
else:
453-
raise TypeError("Granularity can only be specified for plain unsigned `Shape` or `ArrayLayout`")
458+
raise TypeError("Granularity can only be specified for memories whose shape "
459+
"is unsigned or data.ArrayLayout")
454460
super().__init__({
455461
"en": wiring.In(en_width),
456462
"addr": wiring.In(addr_width),
@@ -486,18 +492,21 @@ def __repr__(self):
486492

487493
def __init__(self, signature, *, memory, domain, path=None, src_loc_at=0):
488494
if not isinstance(signature, WritePort.Signature):
489-
raise TypeError(f"Expected `WritePort.Signature`, not {signature!r}")
495+
raise TypeError(f"Expected signature to be WritePort.Signature, not {signature!r}")
490496
if memory is not None: # may be None if created via `Signature.create()`
491497
if not isinstance(memory, Memory):
492-
raise TypeError(f"Expected `Memory` or `None`, not {memory!r}")
493-
if signature.shape != memory.shape or Shape.cast(signature.shape) != Shape.cast(memory.shape):
494-
raise ValueError(f"Memory shape {memory.shape!r} doesn't match port shape {signature.shape!r}")
498+
raise TypeError(f"Expected memory to be Memory or None, not {memory!r}")
499+
if (signature.shape != memory.shape or
500+
Shape.cast(signature.shape) != Shape.cast(memory.shape)):
501+
raise ValueError(f"Memory shape {memory.shape!r} doesn't match "
502+
f"port shape {signature.shape!r}")
495503
if signature.addr_width != ceil_log2(memory.depth):
496-
raise ValueError(f"Memory address width {ceil_log2(memory.depth)!r} doesn't match port address width {signature.addr_width!r}")
504+
raise ValueError(f"Memory address width {ceil_log2(memory.depth)!r} doesn't match "
505+
f"port address width {signature.addr_width!r}")
497506
if not isinstance(domain, str):
498-
raise TypeError(f"Domain has to be a string, not {domain!r}")
507+
raise TypeError(f"Domain must be a string, not {domain!r}")
499508
if domain == "comb":
500-
raise ValueError("Write port domain cannot be \"comb\"")
509+
raise ValueError("Write ports cannot be asynchronous")
501510
self._signature = signature
502511
self._memory = memory
503512
self._domain = domain

tests/test_lib_memory.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -58,28 +58,29 @@ def test_signature(self):
5858

5959
def test_signature_wrong(self):
6060
with self.assertRaisesRegex(TypeError,
61-
"^`addr_width` must be a non-negative int, not -2$"):
61+
r"^Address width must be a non-negative integer, not -2$"):
6262
memory.WritePort.Signature(addr_width=-2, shape=8)
6363
with self.assertRaisesRegex(TypeError,
64-
"^Granularity must be a non-negative int or None, not -2$"):
64+
r"^Granularity must be a non-negative integer or None, not -2$"):
6565
memory.WritePort.Signature(addr_width=4, shape=8, granularity=-2)
6666
with self.assertRaisesRegex(ValueError,
67-
"^Granularity cannot be specified with signed shape$"):
67+
r"^Granularity cannot be specified for a memory with a signed shape$"):
6868
memory.WritePort.Signature(addr_width=2, shape=signed(8), granularity=2)
6969
with self.assertRaisesRegex(TypeError,
70-
"^Granularity can only be specified for plain unsigned `Shape` or `ArrayLayout`$"):
70+
r"^Granularity can only be specified for memories whose shape is unsigned or "
71+
r"data.ArrayLayout$"):
7172
memory.WritePort.Signature(addr_width=2, shape=MyStruct, granularity=2)
7273
with self.assertRaisesRegex(ValueError,
73-
"^Granularity must be positive$"):
74+
r"^Granularity must be positive$"):
7475
memory.WritePort.Signature(addr_width=2, shape=8, granularity=0)
7576
with self.assertRaisesRegex(ValueError,
76-
"^Granularity must be positive$"):
77+
r"^Granularity must be positive$"):
7778
memory.WritePort.Signature(addr_width=2, shape=data.ArrayLayout(8, 8), granularity=0)
7879
with self.assertRaisesRegex(ValueError,
79-
"^Granularity must divide data width$"):
80+
r"^Granularity must evenly divide data width$"):
8081
memory.WritePort.Signature(addr_width=2, shape=8, granularity=3)
8182
with self.assertRaisesRegex(ValueError,
82-
"^Granularity must divide data array length$"):
83+
r"^Granularity must evenly divide data array length$"):
8384
memory.WritePort.Signature(addr_width=2, shape=data.ArrayLayout(8, 8), granularity=3)
8485

8586
def test_signature_eq(self):
@@ -134,17 +135,17 @@ def test_constructor(self):
134135
def test_constructor_wrong(self):
135136
signature = memory.ReadPort.Signature(shape=8, addr_width=4)
136137
with self.assertRaisesRegex(TypeError,
137-
r"^Expected `WritePort.Signature`, not ReadPort.Signature\(.*\)$"):
138+
r"^Expected signature to be WritePort.Signature, not ReadPort.Signature\(.*\)$"):
138139
memory.WritePort(signature, memory=None, domain="sync")
139140
signature = memory.WritePort.Signature(shape=8, addr_width=4, granularity=2)
140141
with self.assertRaisesRegex(TypeError,
141-
r"^Domain has to be a string, not None$"):
142+
r"^Domain must be a string, not None$"):
142143
memory.WritePort(signature, memory=None, domain=None)
143144
with self.assertRaisesRegex(TypeError,
144-
r"^Expected `Memory` or `None`, not 'a'$"):
145+
r"^Expected memory to be Memory or None, not 'a'$"):
145146
memory.WritePort(signature, memory="a", domain="sync")
146147
with self.assertRaisesRegex(ValueError,
147-
r"^Write port domain cannot be \"comb\"$"):
148+
r"^Write ports cannot be asynchronous$"):
148149
memory.WritePort(signature, memory=None, domain="comb")
149150
signature = memory.WritePort.Signature(shape=8, addr_width=4)
150151
m = memory.Memory(depth=8, shape=8, init=[])
@@ -186,7 +187,7 @@ def test_signature(self):
186187

187188
def test_signature_wrong(self):
188189
with self.assertRaisesRegex(TypeError,
189-
"^`addr_width` must be a non-negative int, not -2$"):
190+
"^Address width must be a non-negative integer, not -2$"):
190191
memory.ReadPort.Signature(addr_width=-2, shape=8)
191192

192193
def test_signature_eq(self):
@@ -245,14 +246,14 @@ def test_constructor(self):
245246
def test_constructor_wrong(self):
246247
signature = memory.WritePort.Signature(shape=8, addr_width=4)
247248
with self.assertRaisesRegex(TypeError,
248-
r"^Expected `ReadPort.Signature`, not WritePort.Signature\(.*\)$"):
249+
r"^Expected signature to be ReadPort.Signature, not WritePort.Signature\(.*\)$"):
249250
memory.ReadPort(signature, memory=None, domain="sync")
250251
signature = memory.ReadPort.Signature(shape=8, addr_width=4)
251252
with self.assertRaisesRegex(TypeError,
252-
r"^Domain has to be a string, not None$"):
253+
r"^Domain must be a string, not None$"):
253254
memory.ReadPort(signature, memory=None, domain=None)
254255
with self.assertRaisesRegex(TypeError,
255-
r"^Expected `Memory` or `None`, not 'a'$"):
256+
r"^Expected memory to be Memory or None, not 'a'$"):
256257
memory.ReadPort(signature, memory="a", domain="sync")
257258
signature = memory.ReadPort.Signature(shape=8, addr_width=4)
258259
m = memory.Memory(depth=8, shape=8, init=[])
@@ -266,15 +267,15 @@ def test_constructor_wrong(self):
266267
m = memory.Memory(depth=16, shape=8, init=[])
267268
port = m.read_port()
268269
with self.assertRaisesRegex(TypeError,
269-
r"^`transparent_for` must contain only `WritePort` instances$"):
270+
r"^Transparency set must contain only WritePort instances$"):
270271
memory.ReadPort(signature, memory=m, domain="sync", transparent_for=[port])
271272
write_port = m.write_port()
272273
m2 = memory.Memory(depth=16, shape=8, init=[])
273274
with self.assertRaisesRegex(ValueError,
274-
r"^Transparent write ports must belong to the same memory$"):
275+
r"^Ports in transparency set must belong to the same memory$"):
275276
memory.ReadPort(signature, memory=m2, domain="sync", transparent_for=[write_port])
276277
with self.assertRaisesRegex(ValueError,
277-
r"^Transparent write ports must belong to the same domain$"):
278+
r"^Ports in transparency set must belong to the same domain$"):
278279
memory.ReadPort(signature, memory=m, domain="other", transparent_for=[write_port])
279280

280281

0 commit comments

Comments
 (0)