2024-02-14 03:27:39 -07:00
|
|
|
# amaranth: UnusedElaboratable=no
|
|
|
|
|
2024-03-13 11:54:42 -06:00
|
|
|
from amaranth.hdl import *
|
2024-02-14 03:27:39 -07:00
|
|
|
from amaranth.hdl._mem import MemoryInstance
|
2024-03-13 11:54:42 -06:00
|
|
|
from amaranth.lib import memory, data
|
2024-02-14 03:27:39 -07:00
|
|
|
from amaranth.lib.wiring import In, Out, SignatureMembers
|
|
|
|
|
|
|
|
from .utils import *
|
|
|
|
|
2024-03-13 11:54:42 -06:00
|
|
|
class MyStruct(data.Struct):
|
2024-02-14 03:27:39 -07:00
|
|
|
a: unsigned(3)
|
|
|
|
b: signed(2)
|
|
|
|
|
|
|
|
|
|
|
|
class WritePortTestCase(FHDLTestCase):
|
|
|
|
def test_signature(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
sig = memory.WritePort.Signature(addr_width=2, shape=signed(4))
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(sig.addr_width, 2)
|
|
|
|
self.assertEqual(sig.shape, signed(4))
|
|
|
|
self.assertEqual(sig.granularity, None)
|
|
|
|
self.assertEqual(sig.members, SignatureMembers({
|
|
|
|
"addr": In(2),
|
|
|
|
"data": In(signed(4)),
|
|
|
|
"en": In(1),
|
|
|
|
}))
|
2024-03-13 11:54:42 -06:00
|
|
|
sig = memory.WritePort.Signature(addr_width=2, shape=8, granularity=2)
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(sig.addr_width, 2)
|
|
|
|
self.assertEqual(sig.shape, 8)
|
|
|
|
self.assertEqual(sig.members, SignatureMembers({
|
|
|
|
"addr": In(2),
|
|
|
|
"data": In(8),
|
|
|
|
"en": In(4),
|
|
|
|
}))
|
2024-03-13 11:54:42 -06:00
|
|
|
sig = memory.WritePort.Signature(addr_width=2, shape=data.ArrayLayout(9, 8), granularity=2)
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(sig.addr_width, 2)
|
2024-03-13 11:54:42 -06:00
|
|
|
self.assertEqual(sig.shape, data.ArrayLayout(9, 8))
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(sig.members, SignatureMembers({
|
|
|
|
"addr": In(2),
|
2024-03-13 11:54:42 -06:00
|
|
|
"data": In(data.ArrayLayout(9, 8)),
|
2024-02-14 03:27:39 -07:00
|
|
|
"en": In(4),
|
|
|
|
}))
|
2024-03-13 11:54:42 -06:00
|
|
|
sig = memory.WritePort.Signature(addr_width=2, shape=0, granularity=0)
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(sig.addr_width, 2)
|
|
|
|
self.assertEqual(sig.shape, 0)
|
|
|
|
self.assertEqual(sig.members, SignatureMembers({
|
|
|
|
"addr": In(2),
|
|
|
|
"data": In(0),
|
|
|
|
"en": In(0),
|
|
|
|
}))
|
2024-03-13 11:54:42 -06:00
|
|
|
sig = memory.WritePort.Signature(addr_width=2, shape=data.ArrayLayout(9, 0), granularity=0)
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(sig.addr_width, 2)
|
2024-03-13 11:54:42 -06:00
|
|
|
self.assertEqual(sig.shape, data.ArrayLayout(9, 0))
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(sig.members, SignatureMembers({
|
|
|
|
"addr": In(2),
|
2024-03-13 11:54:42 -06:00
|
|
|
"data": In(data.ArrayLayout(9, 0)),
|
2024-02-14 03:27:39 -07:00
|
|
|
"en": In(0),
|
|
|
|
}))
|
|
|
|
|
|
|
|
def test_signature_wrong(self):
|
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
"^`addr_width` must be a non-negative int, not -2$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort.Signature(addr_width=-2, shape=8)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
"^Granularity must be a non-negative int or None, not -2$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort.Signature(addr_width=4, shape=8, granularity=-2)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
"^Granularity cannot be specified with signed shape$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort.Signature(addr_width=2, shape=signed(8), granularity=2)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
"^Granularity can only be specified for plain unsigned `Shape` or `ArrayLayout`$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort.Signature(addr_width=2, shape=MyStruct, granularity=2)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
"^Granularity must be positive$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort.Signature(addr_width=2, shape=8, granularity=0)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
"^Granularity must be positive$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort.Signature(addr_width=2, shape=data.ArrayLayout(8, 8), granularity=0)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
"^Granularity must divide data width$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort.Signature(addr_width=2, shape=8, granularity=3)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
"^Granularity must divide data array length$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort.Signature(addr_width=2, shape=data.ArrayLayout(8, 8), granularity=3)
|
2024-02-14 03:27:39 -07:00
|
|
|
|
2024-02-28 01:56:34 -07:00
|
|
|
def test_signature_eq(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
sig = memory.WritePort.Signature(addr_width=2, shape=8)
|
|
|
|
self.assertEqual(sig, memory.WritePort.Signature(addr_width=2, shape=8))
|
|
|
|
self.assertNotEqual(sig, memory.WritePort.Signature(addr_width=2, shape=7))
|
|
|
|
self.assertNotEqual(sig, memory.WritePort.Signature(addr_width=1, shape=8))
|
|
|
|
self.assertNotEqual(sig, memory.WritePort.Signature(addr_width=2, shape=8, granularity=8))
|
|
|
|
sig = memory.WritePort.Signature(addr_width=2, shape=8, granularity=4)
|
|
|
|
self.assertEqual(sig, memory.WritePort.Signature(addr_width=2, shape=8, granularity=4))
|
|
|
|
self.assertNotEqual(sig, memory.WritePort.Signature(addr_width=2, shape=8, granularity=8))
|
2024-02-28 01:56:34 -07:00
|
|
|
|
2024-02-14 03:27:39 -07:00
|
|
|
def test_constructor(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
signature = memory.WritePort.Signature(shape=MyStruct, addr_width=4)
|
|
|
|
port = memory.WritePort(signature, memory=None, domain="sync")
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(port.signature, signature)
|
|
|
|
self.assertIsNone(port.memory)
|
|
|
|
self.assertEqual(port.domain, "sync")
|
|
|
|
self.assertIsInstance(port.addr, Signal)
|
|
|
|
self.assertEqual(port.addr.shape(), unsigned(4))
|
2024-03-13 11:54:42 -06:00
|
|
|
self.assertIsInstance(port.data, data.View)
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(port.data.shape(), MyStruct)
|
|
|
|
self.assertIsInstance(port.en, Signal)
|
|
|
|
self.assertEqual(port.en.shape(), unsigned(1))
|
|
|
|
|
2024-03-13 11:54:42 -06:00
|
|
|
signature = memory.WritePort.Signature(shape=8, addr_width=4, granularity=2)
|
|
|
|
port = memory.WritePort(signature, memory=None, domain="sync")
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(port.signature, signature)
|
|
|
|
self.assertIsNone(port.memory)
|
|
|
|
self.assertEqual(port.domain, "sync")
|
|
|
|
self.assertIsInstance(port.addr, Signal)
|
|
|
|
self.assertEqual(port.addr.shape(), unsigned(4))
|
|
|
|
self.assertIsInstance(port.data, Signal)
|
|
|
|
self.assertEqual(port.data.shape(), unsigned(8))
|
|
|
|
self.assertIsInstance(port.en, Signal)
|
|
|
|
self.assertEqual(port.en.shape(), unsigned(4))
|
|
|
|
|
2024-03-13 11:54:42 -06:00
|
|
|
m = memory.Memory(depth=16, shape=8, init=[])
|
|
|
|
port = memory.WritePort(signature, memory=m, domain="sync")
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertIs(port.memory, m)
|
|
|
|
self.assertEqual(m.w_ports, (port,))
|
|
|
|
|
|
|
|
def test_constructor_wrong(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
signature = memory.ReadPort.Signature(shape=8, addr_width=4)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Expected `WritePort.Signature`, not ReadPort.Signature\(.*\)$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort(signature, memory=None, domain="sync")
|
|
|
|
signature = memory.WritePort.Signature(shape=8, addr_width=4, granularity=2)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Domain has to be a string, not None$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort(signature, memory=None, domain=None)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Expected `Memory` or `None`, not 'a'$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort(signature, memory="a", domain="sync")
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
r"^Write port domain cannot be \"comb\"$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort(signature, memory=None, domain="comb")
|
|
|
|
signature = memory.WritePort.Signature(shape=8, addr_width=4)
|
|
|
|
m = memory.Memory(depth=8, shape=8, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
r"^Memory address width 3 doesn't match port address width 4$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort(signature, memory=m, domain="sync")
|
|
|
|
m = memory.Memory(depth=16, shape=signed(8), init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
r"^Memory shape signed\(8\) doesn't match port shape 8$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.WritePort(signature, memory=m, domain="sync")
|
2024-02-14 03:27:39 -07:00
|
|
|
|
|
|
|
|
|
|
|
class ReadPortTestCase(FHDLTestCase):
|
|
|
|
def test_signature(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
sig = memory.ReadPort.Signature(addr_width=2, shape=signed(4))
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(sig.addr_width, 2)
|
|
|
|
self.assertEqual(sig.shape, signed(4))
|
|
|
|
self.assertEqual(sig.members, SignatureMembers({
|
|
|
|
"addr": In(2),
|
|
|
|
"data": Out(signed(4)),
|
|
|
|
"en": In(1, init=1),
|
|
|
|
}))
|
2024-03-13 11:54:42 -06:00
|
|
|
sig = memory.ReadPort.Signature(addr_width=2, shape=8)
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(sig.addr_width, 2)
|
|
|
|
self.assertEqual(sig.shape, 8)
|
|
|
|
self.assertEqual(sig.members, SignatureMembers({
|
|
|
|
"addr": In(2),
|
|
|
|
"data": Out(8),
|
|
|
|
"en": In(1, init=1),
|
|
|
|
}))
|
2024-03-13 11:54:42 -06:00
|
|
|
sig = memory.ReadPort.Signature(addr_width=2, shape=MyStruct)
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(sig.addr_width, 2)
|
|
|
|
self.assertEqual(sig.shape, MyStruct)
|
|
|
|
self.assertEqual(sig.members, SignatureMembers({
|
|
|
|
"addr": In(2),
|
|
|
|
"data": Out(MyStruct),
|
|
|
|
"en": In(1, init=1),
|
|
|
|
}))
|
|
|
|
|
|
|
|
def test_signature_wrong(self):
|
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
"^`addr_width` must be a non-negative int, not -2$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.ReadPort.Signature(addr_width=-2, shape=8)
|
2024-02-14 03:27:39 -07:00
|
|
|
|
2024-02-28 01:56:34 -07:00
|
|
|
def test_signature_eq(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
sig = memory.ReadPort.Signature(addr_width=2, shape=8)
|
|
|
|
self.assertEqual(sig, memory.ReadPort.Signature(addr_width=2, shape=8))
|
|
|
|
self.assertNotEqual(sig, memory.ReadPort.Signature(addr_width=2, shape=7))
|
|
|
|
self.assertNotEqual(sig, memory.ReadPort.Signature(addr_width=1, shape=8))
|
|
|
|
self.assertNotEqual(sig, memory.WritePort.Signature(addr_width=2, shape=8))
|
2024-02-28 01:56:34 -07:00
|
|
|
|
2024-02-14 03:27:39 -07:00
|
|
|
def test_constructor(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
signature = memory.ReadPort.Signature(shape=MyStruct, addr_width=4)
|
|
|
|
port = memory.ReadPort(signature, memory=None, domain="sync")
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(port.signature, signature)
|
|
|
|
self.assertIsNone(port.memory)
|
|
|
|
self.assertEqual(port.domain, "sync")
|
|
|
|
self.assertIsInstance(port.addr, Signal)
|
|
|
|
self.assertEqual(port.addr.shape(), unsigned(4))
|
2024-03-13 11:54:42 -06:00
|
|
|
self.assertIsInstance(port.data, data.View)
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(port.data.shape(), MyStruct)
|
|
|
|
self.assertIsInstance(port.en, Signal)
|
|
|
|
self.assertEqual(port.en.shape(), unsigned(1))
|
|
|
|
self.assertEqual(port.transparent_for, ())
|
|
|
|
|
2024-03-13 11:54:42 -06:00
|
|
|
signature = memory.ReadPort.Signature(shape=8, addr_width=4)
|
|
|
|
port = memory.ReadPort(signature, memory=None, domain="comb")
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(port.signature, signature)
|
|
|
|
self.assertIsNone(port.memory)
|
|
|
|
self.assertEqual(port.domain, "comb")
|
|
|
|
self.assertIsInstance(port.addr, Signal)
|
|
|
|
self.assertEqual(port.addr.shape(), unsigned(4))
|
|
|
|
self.assertIsInstance(port.data, Signal)
|
|
|
|
self.assertEqual(port.data.shape(), unsigned(8))
|
|
|
|
self.assertIsInstance(port.en, Const)
|
|
|
|
self.assertEqual(port.en.shape(), unsigned(1))
|
|
|
|
self.assertEqual(port.en.value, 1)
|
|
|
|
self.assertEqual(port.transparent_for, ())
|
|
|
|
|
2024-03-13 11:54:42 -06:00
|
|
|
m = memory.Memory(depth=16, shape=8, init=[])
|
|
|
|
port = memory.ReadPort(signature, memory=m, domain="sync")
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertIs(port.memory, m)
|
|
|
|
self.assertEqual(m.r_ports, (port,))
|
|
|
|
write_port = m.write_port()
|
2024-03-13 11:54:42 -06:00
|
|
|
port = memory.ReadPort(signature, memory=m, domain="sync", transparent_for=[write_port])
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertIs(port.memory, m)
|
|
|
|
self.assertEqual(port.transparent_for, (write_port,))
|
|
|
|
|
|
|
|
def test_constructor_wrong(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
signature = memory.WritePort.Signature(shape=8, addr_width=4)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Expected `ReadPort.Signature`, not WritePort.Signature\(.*\)$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.ReadPort(signature, memory=None, domain="sync")
|
|
|
|
signature = memory.ReadPort.Signature(shape=8, addr_width=4)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Domain has to be a string, not None$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.ReadPort(signature, memory=None, domain=None)
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Expected `Memory` or `None`, not 'a'$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.ReadPort(signature, memory="a", domain="sync")
|
|
|
|
signature = memory.ReadPort.Signature(shape=8, addr_width=4)
|
|
|
|
m = memory.Memory(depth=8, shape=8, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
r"^Memory address width 3 doesn't match port address width 4$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.ReadPort(signature, memory=m, domain="sync")
|
|
|
|
m = memory.Memory(depth=16, shape=signed(8), init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
r"^Memory shape signed\(8\) doesn't match port shape 8$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.ReadPort(signature, memory=m, domain="sync")
|
|
|
|
m = memory.Memory(depth=16, shape=8, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
port = m.read_port()
|
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^`transparent_for` must contain only `WritePort` instances$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.ReadPort(signature, memory=m, domain="sync", transparent_for=[port])
|
2024-02-14 03:27:39 -07:00
|
|
|
write_port = m.write_port()
|
2024-03-13 11:54:42 -06:00
|
|
|
m2 = memory.Memory(depth=16, shape=8, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
r"^Transparent write ports must belong to the same memory$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.ReadPort(signature, memory=m2, domain="sync", transparent_for=[write_port])
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
r"^Transparent write ports must belong to the same domain$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.ReadPort(signature, memory=m, domain="other", transparent_for=[write_port])
|
2024-02-14 03:27:39 -07:00
|
|
|
|
|
|
|
|
|
|
|
class MemoryTestCase(FHDLTestCase):
|
|
|
|
def test_constructor(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
m = memory.Memory(shape=8, depth=4, init=[1, 2, 3])
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(m.shape, 8)
|
|
|
|
self.assertEqual(m.depth, 4)
|
|
|
|
self.assertEqual(m.init.shape, 8)
|
|
|
|
self.assertEqual(m.init.depth, 4)
|
|
|
|
self.assertEqual(m.attrs, {})
|
2024-03-13 11:54:42 -06:00
|
|
|
self.assertIsInstance(m.init, memory.Memory.Init)
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(list(m.init), [1, 2, 3, 0])
|
|
|
|
self.assertEqual(m.init._raw, [1, 2, 3, 0])
|
|
|
|
self.assertRepr(m.init, "Memory.Init([1, 2, 3, 0])")
|
|
|
|
self.assertEqual(m.r_ports, ())
|
|
|
|
self.assertEqual(m.w_ports, ())
|
|
|
|
|
|
|
|
def test_constructor_shapecastable(self):
|
|
|
|
init = [
|
|
|
|
{"a": 0, "b": 1},
|
|
|
|
{"a": 2, "b": 3},
|
|
|
|
]
|
2024-03-13 11:54:42 -06:00
|
|
|
m = memory.Memory(shape=MyStruct, depth=4, init=init, attrs={"ram_style": "block"})
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(m.shape, MyStruct)
|
|
|
|
self.assertEqual(m.depth, 4)
|
|
|
|
self.assertEqual(m.attrs, {"ram_style": "block"})
|
2024-03-13 11:54:42 -06:00
|
|
|
self.assertIsInstance(m.init, memory.Memory.Init)
|
2024-02-14 03:27:39 -07:00
|
|
|
self.assertEqual(list(m.init), [{"a": 0, "b": 1}, {"a": 2, "b": 3}, None, None])
|
|
|
|
self.assertEqual(m.init._raw, [8, 0x1a, 0, 0])
|
|
|
|
|
|
|
|
def test_constructor_wrong(self):
|
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Memory depth must be a non-negative integer, not 'a'$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.Memory(shape=8, depth="a", init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Memory depth must be a non-negative integer, not -1$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.Memory(shape=8, depth=-1, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Object 'a' cannot be converted to an Amaranth shape$"):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.Memory(shape="a", depth=3, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
(r"^Memory initialization value at address 1: "
|
|
|
|
r"'str' object cannot be interpreted as an integer$")):
|
2024-03-13 11:54:42 -06:00
|
|
|
memory.Memory(shape=8, depth=4, init=[1, "0"])
|
2024-02-14 03:27:39 -07:00
|
|
|
|
|
|
|
def test_init_set(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
m = memory.Memory(shape=8, depth=4, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
m.init[1] = 2
|
|
|
|
self.assertEqual(list(m.init), [0, 2, 0, 0])
|
|
|
|
self.assertEqual(m.init._raw, [0, 2, 0, 0])
|
|
|
|
m.init[2:] = [4, 5]
|
|
|
|
self.assertEqual(list(m.init), [0, 2, 4, 5])
|
2024-03-13 06:46:39 -06:00
|
|
|
m.init = [6, 7]
|
|
|
|
self.assertEqual(list(m.init), [6, 7, 0, 0])
|
2024-02-14 03:27:39 -07:00
|
|
|
|
|
|
|
def test_init_set_shapecastable(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
m = memory.Memory(shape=MyStruct, depth=4, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
m.init[1] = {"a": 1, "b": 2}
|
|
|
|
self.assertEqual(list(m.init), [None, {"a": 1, "b": 2}, None, None])
|
|
|
|
self.assertEqual(m.init._raw, [0, 0x11, 0, 0])
|
|
|
|
|
|
|
|
def test_init_set_wrong(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
m = memory.Memory(shape=8, depth=4, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^'str' object cannot be interpreted as an integer$"):
|
|
|
|
m.init[0] = "a"
|
2024-03-13 11:54:42 -06:00
|
|
|
m = memory.Memory(shape=MyStruct, depth=4, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
# underlying TypeError message differs between PyPy and CPython
|
|
|
|
with self.assertRaises(TypeError):
|
|
|
|
m.init[0] = 1
|
|
|
|
|
|
|
|
def test_init_set_slice_wrong(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
m = memory.Memory(shape=8, depth=4, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
r"^Changing length of Memory.init is not allowed$"):
|
|
|
|
m.init[1:] = [1, 2]
|
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Deleting items from Memory.init is not allowed$"):
|
|
|
|
del m.init[1:2]
|
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Inserting items into Memory.init is not allowed$"):
|
|
|
|
m.init.insert(1, 3)
|
|
|
|
|
|
|
|
def test_port(self):
|
|
|
|
for depth, addr_width in [
|
|
|
|
(0, 0),
|
|
|
|
(1, 0),
|
|
|
|
(3, 2),
|
|
|
|
(4, 2),
|
|
|
|
(5, 3),
|
|
|
|
]:
|
2024-03-13 11:54:42 -06:00
|
|
|
m = memory.Memory(shape=8, depth=depth, init=[])
|
2024-02-14 03:27:39 -07:00
|
|
|
rp = m.read_port()
|
|
|
|
self.assertEqual(rp.signature.addr_width, addr_width)
|
|
|
|
self.assertEqual(rp.signature.shape, 8)
|
|
|
|
wp = m.write_port()
|
|
|
|
self.assertEqual(wp.signature.addr_width, addr_width)
|
|
|
|
self.assertEqual(wp.signature.shape, 8)
|
|
|
|
self.assertEqual(m.r_ports, (rp,))
|
|
|
|
self.assertEqual(m.w_ports, (wp,))
|
|
|
|
|
|
|
|
def test_elaborate(self):
|
2024-03-13 11:54:42 -06:00
|
|
|
m = memory.Memory(shape=MyStruct, depth=4, init=[{"a": 1, "b": 2}])
|
2024-02-14 03:27:39 -07:00
|
|
|
wp = m.write_port()
|
|
|
|
rp0 = m.read_port(domain="sync", transparent_for=[wp])
|
|
|
|
rp1 = m.read_port(domain="comb")
|
|
|
|
f = m.elaborate(None)
|
|
|
|
self.assertIsInstance(f, MemoryInstance)
|
|
|
|
self.assertIs(f._identity, m._identity)
|
|
|
|
self.assertEqual(f._depth, 4)
|
|
|
|
self.assertEqual(f._width, 5)
|
|
|
|
self.assertEqual(f._init, (0x11, 0, 0, 0))
|
|
|
|
self.assertEqual(f._write_ports[0]._domain, "sync")
|
|
|
|
self.assertEqual(f._write_ports[0]._granularity, 5)
|
|
|
|
self.assertIs(f._write_ports[0]._addr, wp.addr)
|
|
|
|
self.assertIs(f._write_ports[0]._data, wp.data.as_value())
|
|
|
|
self.assertIs(f._write_ports[0]._en, wp.en)
|
|
|
|
self.assertEqual(f._read_ports[0]._domain, "sync")
|
|
|
|
self.assertEqual(f._read_ports[0]._transparent_for, (0,))
|
|
|
|
self.assertIs(f._read_ports[0]._addr, rp0.addr)
|
|
|
|
self.assertIs(f._read_ports[0]._data, rp0.data.as_value())
|
|
|
|
self.assertIs(f._read_ports[0]._en, rp0.en)
|
|
|
|
self.assertEqual(f._read_ports[1]._domain, "comb")
|
|
|
|
self.assertEqual(f._read_ports[1]._transparent_for, ())
|
|
|
|
self.assertIs(f._read_ports[1]._addr, rp1.addr)
|
|
|
|
self.assertIs(f._read_ports[1]._data, rp1.data.as_value())
|
|
|
|
self.assertIs(f._read_ports[1]._en, rp1.en)
|