Skip to content

Unclear error message when using an Array as port #290

Closed
@nmigen-issue-migration

Description

@nmigen-issue-migration

Issue by ZirconiumX
Wednesday Jan 01, 2020 at 18:25 GMT
Originally opened as m-labs/nmigen#290


When trying to use an Array as a port, nMigen yields the following traceback, which doesn't make it clear that Arrays are not permitted as Verilog ports.

Traceback (most recent call last):
  File "gpr.py", line 64, in <module>
    print(verilog.convert(dut, ports=ports))
  File "/usr/local/lib/python3.7/dist-packages/nmigen-0.2.dev13+g476ce15-py3.7.egg/nmigen/back/verilog.py", line 76, in convert
    rtlil_text = rtlil.convert(*args, **kwargs)
  File "/usr/local/lib/python3.7/dist-packages/nmigen-0.2.dev13+g476ce15-py3.7.egg/nmigen/back/rtlil.py", line 1010, in convert
    fragment = ir.Fragment.get(elaboratable, platform).prepare(**kwargs)
  File "/usr/local/lib/python3.7/dist-packages/nmigen-0.2.dev13+g476ce15-py3.7.egg/nmigen/hdl/ir.py", line 556, in prepare
    fragment._propagate_ports(ports=(*ports, *new_ports), all_undef_as_ports=False)
  File "/usr/local/lib/python3.7/dist-packages/nmigen-0.2.dev13+g476ce15-py3.7.egg/nmigen/hdl/xfrm.py", line 128, in on_value
    new_value = self.on_unknown_value(value)
  File "/usr/local/lib/python3.7/dist-packages/nmigen-0.2.dev13+g476ce15-py3.7.egg/nmigen/hdl/xfrm.py", line 86, in on_unknown_value
    raise TypeError("Cannot transform value {!r}".format(value)) # :nocov:
TypeError: Cannot transform value (array mutable [(array mutable [(sig $signal)]), (array mutable [(sig $signal)])])

Source used to generate this traceback:

from nmigen import *
from nmigen.back import rtlil, verilog


READ_PORTS_PER_CHANNEL  = 2
WRITE_PORTS_PER_CHANNEL = 1
CHANNELS                = 2
REGISTERS               = 32


class Gpr(Elaboratable):
    def __init__(self, rwidth=32):
        self.rwidth = rwidth
        self.rdepth = (REGISTERS - 1).bit_length()

        self.i_wr_a = Array(Array(Signal(self.rdepth) for _ in range(WRITE_PORTS_PER_CHANNEL)) for _ in range(CHANNELS))
        self.i_wr_d = Array(Array(Signal(rwidth) for _ in range(WRITE_PORTS_PER_CHANNEL)) for _ in range(CHANNELS))
        self.i_rd_a = Array(Array(Signal(self.rdepth) for _ in range(READ_PORTS_PER_CHANNEL)) for _ in range(CHANNELS))
        self.o_rd_d = Array(Array(Signal(rwidth) for _ in range(READ_PORTS_PER_CHANNEL)) for _ in range(CHANNELS))

    def elaborate(self, platform):
        m = Module()

        select  = Memory(width=CHANNELS, depth=self.rdepth)
        regfile = Array(Memory(width=self.rwidth, depth=self.rdepth) for _ in range(CHANNELS))
        readmux = Array(Array(Array(Signal(self.rwidth)) for _ in range(CHANNELS) for _ in range(READ_PORTS_PER_CHANNEL)) for _ in range(CHANNELS))

        for chan in range(CHANNELS):
            # Write ports
            for port in range(WRITE_PORTS_PER_CHANNEL):
                m.submodules["reg_write_c{}p{}".format(chan, port)] = reg_write_port = regfile[chan].write_port()
                m.submodules["sel_write_c{}p{}".format(chan, port)] = sel_write_port = select.write_port()
                m.d.comb += [
                    reg_write_port.addr.eq(self.i_wr_a[chan][port]),
                    reg_write_port.data.eq(self.i_wr_d[chan][port]),
                    sel_write_port.addr.eq(self.i_wr_a[chan][port]),
                    sel_write_port.data.eq(port)
                ]

            # Read ports
            for port in range(READ_PORTS_PER_CHANNEL):
                m.submodules["reg_read_c{}p{}".format(chan, port)] = reg_read_port = regfile[chan].read_port()
                m.submodules["sel_read_c{}p{}".format(chan, port)] = sel_read_port = select.read_port()

                for otherchan in range(CHANNELS):
                    m.d.comb += readmux[otherchan][port][chan].eq(reg_read_port.data)

                m.d.comb += [
                    reg_read_port.addr.eq(self.i_rd_a[chan][port]),
                    sel_read_port.addr.eq(self.i_rd_a[chan][port]),
                    self.o_rd_d[chan][port].eq(readmux[chan][port][sel_read_port.data])
                ]

        return m


dut = Gpr()

ports = [
    dut.i_wr_a, dut.i_wr_d,
    dut.i_rd_a, dut.o_rd_d
]

print(verilog.convert(dut, ports=ports))

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions