Skip to content

vendor, io: fix missing i_domain and o_domain arguments when specializing #1347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions amaranth/lib/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,21 @@ def __init__(self, direction, port, *, i_domain=None, o_domain=None):
if port.direction is Direction.Output and self.direction is not Direction.Output:
raise ValueError(f"Output port cannot be used with {self.direction.name} buffer")

@classmethod
def create_from(cls, buffer):
"""Called on classes which inherit from :class:`FFBuffer` but do not
overload the constructor. This method calls the :class:`FFBuffer`
constructor above to create a new instance.
"""

if not isinstance(buffer, FFBuffer):
raise TypeError(f"'buffer' must be a FFBuffer to create a {cls!r}")

i_domain = getattr(buffer, '_i_domain', None)
o_domain = getattr(buffer, '_o_domain', None)

return cls(buffer.direction, buffer.port, i_domain=i_domain, o_domain=o_domain)

@property
def port(self):
return self._port
Expand Down Expand Up @@ -619,6 +634,21 @@ def __init__(self, direction, port, *, i_domain=None, o_domain=None):
if port.direction is Direction.Output and self.direction is not Direction.Output:
raise ValueError(f"Output port cannot be used with {self.direction.name} buffer")

@classmethod
def create_from(cls, buffer):
"""Called on classes which inherit from :class:`DDRBuffer` but do not
overload the constructor. This method calls the :class:`DDRBuffer`
constructor to create a new instance.
"""

if not isinstance(buffer, DDRBuffer):
raise TypeError(f"'buffer' must be a DDRBuffer to create a {cls!r}")

i_domain = getattr(buffer, '_i_domain', None)
o_domain = getattr(buffer, '_o_domain', None)

return cls(buffer.direction, buffer.port, i_domain=i_domain, o_domain=o_domain)

@property
def port(self):
return self._port
Expand Down
4 changes: 2 additions & 2 deletions amaranth/vendor/_altera.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,9 +475,9 @@ def get_io_buffer(self, buffer):
if isinstance(buffer, io.Buffer):
result = IOBuffer(buffer.direction, buffer.port)
elif isinstance(buffer, io.FFBuffer):
result = FFBuffer(buffer.direction, buffer.port)
result = FFBuffer.create_from(buffer)
elif isinstance(buffer, io.DDRBuffer):
result = DDRBuffer(buffer.direction, buffer.port)
result = DDRBuffer.create_from(buffer)
else:
raise TypeError(f"Unsupported buffer type {buffer!r}") # :nocov:
if buffer.direction is not io.Direction.Output:
Expand Down
4 changes: 2 additions & 2 deletions amaranth/vendor/_gowin.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,9 +543,9 @@ def get_io_buffer(self, buffer):
if isinstance(buffer, io.Buffer):
result = IOBuffer(buffer.direction, buffer.port)
elif isinstance(buffer, io.FFBuffer):
result = FFBuffer(buffer.direction, buffer.port)
result = FFBuffer.create_from(buffer)
elif isinstance(buffer, io.DDRBuffer):
result = DDRBuffer(buffer.direction, buffer.port)
result = DDRBuffer.create_from(buffer)
else:
raise TypeError(f"Unsupported buffer type {buffer!r}") # :nocov:
if buffer.direction is not io.Direction.Output:
Expand Down
8 changes: 4 additions & 4 deletions amaranth/vendor/_lattice.py
Original file line number Diff line number Diff line change
Expand Up @@ -951,14 +951,14 @@ def get_io_buffer(self, buffer):
if isinstance(buffer, io.Buffer):
result = IOBuffer(buffer.direction, buffer.port)
elif isinstance(buffer, io.FFBuffer):
result = FFBuffer(buffer.direction, buffer.port)
result = FFBuffer.create_from(buffer)
elif isinstance(buffer, io.DDRBuffer):
if self.family == "ecp5":
result = DDRBufferECP5(buffer.direction, buffer.port)
result = DDRBufferECP5.create_from(buffer)
elif self.family == "machxo2":
result = DDRBufferMachXO2(buffer.direction, buffer.port)
result = DDRBufferMachXO2.create_from(buffer)
elif self.family == "nexus":
result = DDRBufferNexus(buffer.direction, buffer.port)
result = DDRBufferNexus.create_from(buffer)
else:
raise NotImplementedError # :nocov:
else:
Expand Down
10 changes: 5 additions & 5 deletions amaranth/vendor/_xilinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -1168,16 +1168,16 @@ def get_io_buffer(self, buffer):
if isinstance(buffer, io.Buffer):
result = IOBuffer(buffer.direction, buffer.port)
elif isinstance(buffer, io.FFBuffer):
result = FFBuffer(buffer.direction, buffer.port)
result = FFBuffer.create_from(buffer)
elif isinstance(buffer, io.DDRBuffer):
if self.family in ("virtex2", "virtex2p", "spartan3"):
result = DDRBufferVirtex2(buffer.direction, buffer.port)
result = DDRBufferVirtex2.create_from(buffer)
elif self.family in ("spartan3e", "spartan3a", "spartan3adsp", "spartan6"):
result = DDRBufferSpartan3E(buffer.direction, buffer.port)
result = DDRBufferSpartan3E.create_from(buffer)
elif self.family in ("virtex4", "virtex5", "virtex6", "series7"):
result = DDRBufferVirtex4(buffer.direction, buffer.port)
result = DDRBufferVirtex4.create_from(buffer)
elif self.family in ("ultrascale", "ultrascaleplus"):
result = DDRBufferUltrascale(buffer.direction, buffer.port)
result = DDRBufferUltrascale.create_from(buffer)
else:
raise TypeError(f"Family {self.family} doesn't implement DDR buffers")
else:
Expand Down
94 changes: 94 additions & 0 deletions tests/test_lib_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,53 @@ def test_construct_wrong(self):
r"^Output buffer doesn't have an input domain$"):
FFBuffer("o", port, i_domain="input")

def test_create_from(self):
io = IOPort(4)
port = SingleEndedPort(io)
original_buf = FFBuffer("i", port)
buf = FFBuffer.create_from(original_buf)
self.assertEqual(buf.direction, Direction.Input)
self.assertIs(buf.port, port)
self.assertRepr(buf.signature, "FFBuffer.Signature(Direction.Input, 4).flip()")
self.assertEqual(buf.i_domain, "sync")
with self.assertRaisesRegex(AttributeError,
r"^Input buffer doesn't have an output domain$"):
buf.o_domain
original_buf = FFBuffer("i", port, i_domain="inp")
buf = FFBuffer.create_from(original_buf)
self.assertEqual(buf.i_domain, "inp")
original_buf = FFBuffer("o", port)
buf = FFBuffer.create_from(original_buf)
self.assertEqual(buf.direction, Direction.Output)
self.assertIs(buf.port, port)
self.assertRepr(buf.signature, "FFBuffer.Signature(Direction.Output, 4).flip()")
self.assertEqual(buf.o_domain, "sync")
with self.assertRaisesRegex(AttributeError,
r"^Output buffer doesn't have an input domain$"):
buf.i_domain
original_buf = FFBuffer("o", port, o_domain="out")
buf = FFBuffer.create_from(original_buf)
self.assertEqual(buf.o_domain, "out")
original_buf = FFBuffer("io", port)
buf = FFBuffer.create_from(original_buf)
self.assertEqual(buf.direction, Direction.Bidir)
self.assertIs(buf.port, port)
self.assertRepr(buf.signature, "FFBuffer.Signature(Direction.Bidir, 4).flip()")
self.assertEqual(buf.i_domain, "sync")
self.assertEqual(buf.o_domain, "sync")
original_buf = FFBuffer("io", port, i_domain="input", o_domain="output")
buf = FFBuffer.create_from(original_buf)
self.assertEqual(buf.i_domain, "input")
self.assertEqual(buf.o_domain, "output")

def test_create_from_wrong(self):
io = IOPort(4)
port = SingleEndedPort(io)
original_buf = Buffer("i", port)
with self.assertRaisesRegex(TypeError,
r"^'buffer' must be a FFBuffer to create a <class 'amaranth.lib.io.FFBuffer'>$"):
FFBuffer.create_from(original_buf)

def test_elaborate(self):
io = IOPort(4)

Expand Down Expand Up @@ -714,6 +761,53 @@ def test_construct_wrong(self):
r"^Output buffer doesn't have an input domain$"):
DDRBuffer("o", port, i_domain="input")

def test_create_from(self):
io = IOPort(4)
port = SingleEndedPort(io)
original_buf = DDRBuffer("i", port)
buf = DDRBuffer.create_from(original_buf)
self.assertEqual(buf.direction, Direction.Input)
self.assertIs(buf.port, port)
self.assertRepr(buf.signature, "DDRBuffer.Signature(Direction.Input, 4).flip()")
self.assertEqual(buf.i_domain, "sync")
with self.assertRaisesRegex(AttributeError,
r"^Input buffer doesn't have an output domain$"):
buf.o_domain
original_buf = DDRBuffer("i", port, i_domain="inp")
buf = DDRBuffer.create_from(original_buf)
self.assertEqual(buf.i_domain, "inp")
original_buf = DDRBuffer("o", port)
buf = DDRBuffer.create_from(original_buf)
self.assertEqual(buf.direction, Direction.Output)
self.assertIs(buf.port, port)
self.assertRepr(buf.signature, "DDRBuffer.Signature(Direction.Output, 4).flip()")
self.assertEqual(buf.o_domain, "sync")
with self.assertRaisesRegex(AttributeError,
r"^Output buffer doesn't have an input domain$"):
buf.i_domain
original_buf = DDRBuffer("o", port, o_domain="out")
buf = DDRBuffer.create_from(original_buf)
self.assertEqual(buf.o_domain, "out")
original_buf = DDRBuffer("io", port)
buf = DDRBuffer.create_from(original_buf)
self.assertEqual(buf.direction, Direction.Bidir)
self.assertIs(buf.port, port)
self.assertRepr(buf.signature, "DDRBuffer.Signature(Direction.Bidir, 4).flip()")
self.assertEqual(buf.i_domain, "sync")
self.assertEqual(buf.o_domain, "sync")
original_buf = DDRBuffer("io", port, i_domain="input", o_domain="output")
buf = DDRBuffer.create_from(original_buf)
self.assertEqual(buf.i_domain, "input")
self.assertEqual(buf.o_domain, "output")

def test_create_from_wrong(self):
io = IOPort(4)
port = SingleEndedPort(io)
original_buf = Buffer("i", port)
with self.assertRaisesRegex(TypeError,
r"^'buffer' must be a DDRBuffer to create a <class 'amaranth.lib.io.DDRBuffer'>$"):
DDRBuffer.create_from(original_buf)


class PinSignatureTestCase(FHDLTestCase):
def assertSignatureEqual(self, signature, expected):
Expand Down