glasgow icon indicating copy to clipboard operation
glasgow copied to clipboard

AttributeError: 'EnumView' object has no attribute 'name' when using an `amaranth.lib.enum.Enum` with `glasgow.hardware.assembly.add_rw_register()`

Open joelpmichael opened this issue 5 months ago • 0 comments

Raising bug as requested by @whitequark in Mastodon thread https://aus.social/@jpm/114933922761154443

I'm trying to use an amaranth.lib.enum.Enum with glasgow.hardware.assembly.add_rw_register(), and it is failing with errors:

joel@Joels-iMac-Pro bitstreams % glasgow -vvv run shift-register-cd4021 -V 5        
D: g.cli: Glasgow 0.1.dev2601+g7943521.d20250729 (CPython 3.13.5 on macOS-15.5-x86_64-i386-64bit-Mach-O)
D: g.hardware.device: found revC3 device with serial C3-20240518T195949Z
W: g.applet.interface.CD4021: applet is PREVIEW QUALITY and may CORRUPT DATA
D: g.applet.interface.CD4021: setting port A voltage to 5.00 V
D: g.applet.interface.CD4021: setting port B voltage to 5.00 V
D: g.applet.interface.CD4021: assigning pin clock to A1
D: g.applet.interface.CD4021: assigning pin data to A0
D: g.applet.interface.CD4021: assigning pin latch to A2
Traceback (most recent call last):
  File "/Users/joel/.local/pipx/venvs/glasgow/bin/glasgow", line 8, in <module>
    sys.exit(run_main())
             ~~~~~~~~^^
  File "/Users/joel/.local/pipx/venvs/glasgow/lib/python3.13/site-packages/glasgow/cli.py", line 1056, in run_main
    exit(asyncio.new_event_loop().run_until_complete(main()))
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
  File "/usr/local/Cellar/[email protected]/3.13.5/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py", line 725, in run_until_complete
    return future.result()
           ~~~~~~~~~~~~~^^
  File "/Users/joel/.local/pipx/venvs/glasgow/lib/python3.13/site-packages/glasgow/cli.py", line 653, in main
    applet, target = _applet(assembly, args)
                     ~~~~~~~^^^^^^^^^^^^^^^^
  File "/Users/joel/.local/pipx/venvs/glasgow/lib/python3.13/site-packages/glasgow/cli.py", line 469, in _applet
    applet.build(args)
    ~~~~~~~~~~~~^^^^^^
  File "/Users/joel/.local/pipx/venvs/glasgow/lib/python3.13/site-packages/glasgow/applet/interface/CD4021/__init__.py", line 259, in build
    self.ShiftRegisterCD4021_iface = ShiftRegisterCD4021Interface(
                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        self.logger,
        ^^^^^^^^^^^^
    ...<4 lines>...
        num_bits=args.num_bits,
        ^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/joel/.local/pipx/venvs/glasgow/lib/python3.13/site-packages/glasgow/applet/interface/CD4021/__init__.py", line 169, in __init__
    self._reg_mode = assembly.add_rw_register(component.reg_mode)
                     ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
  File "/Users/joel/.local/pipx/venvs/glasgow/lib/python3.13/site-packages/glasgow/hardware/assembly.py", line 555, in add_rw_register
    address=2 + len(self._registers), shape=signal.shape(), name=signal.name)
                                                                 ^^^^^^^^^^^
AttributeError: 'EnumView' object has no attribute 'name'

Turning these into a Python enum.Enum works fine, with the appropriate code adjustments to use enum.Enum.value where necessary.

Code snippets in question:


class CD4021Mode(enum.Enum, shape=range(4)):
    IDLE = 0  # No command, component is allowed to run
    STOP = 1  # Stop processing
    LATCH = 2  # Perform latch + data reads
    DATA = 3  # Perform data reads only

...

class ShiftRegisterCD4021Component(wiring.Component):
    def __init__(self, ports, num_bits: int = 8):
        if num_bits < 2:
            raise ValueError("num_bits must be 2 or more")

        self._ports = ports
        self._num_bits = num_bits

        self._reg_state = Signal(CD4021State, init=CD4021State.LATCH)
        self._reg_data = Signal(self._num_bits + 1, init=0)

        super().__init__(
            {
                "reg_active": Out(
                    1,
                    init=0,
                ),  # will be set to 1 when component is busy sampling data
                "reg_mode": In(
                    CD4021Mode,
                ),  # requested working mode, reset to IDLE to start working
                "stream_result": Out(
                    stream.Signature(self._num_bits),
                ),  # output data stream
            }
        )

...

class ShiftRegisterCD4021Interface:
    def __init__(
        self,
        logger: logging.Logger,
        assembly: AbstractAssembly,
        *,
        clock: GlasgowPin,
        data: GlasgowPin,
        latch: GlasgowPin,
        num_bits: int,
    ):
        self._logger = logger
        self._level = logging.DEBUG if self._logger.name == __name__ else logging.TRACE

        ports = assembly.add_port_group(clock=clock, data=data, latch=latch)
        component = assembly.add_submodule(
            ShiftRegisterCD4021Component(ports, num_bits=num_bits), name="cd4021"
        )
        self._result_pipe = assembly.add_in_pipe(component.stream_result)
        self._reg_mode = assembly.add_rw_register(component.reg_mode)
        self._reg_active = assembly.add_ro_register(component.reg_active)

...

class ShiftRegisterCD4021Applet(GlasgowAppletV2):
...
    def build(self, args):
        with self.assembly.add_applet(self):
            # FIXME - detect requested voltage, info if < 5V, warn if < 3V
            self.assembly.use_voltage(args.voltage)
            self.ShiftRegisterCD4021_iface = ShiftRegisterCD4021Interface(
                self.logger,
                self.assembly,
                clock=args.clock,
                data=args.data,
                latch=args.latch,
                num_bits=args.num_bits,
            )
...

joelpmichael avatar Jul 29 '25 03:07 joelpmichael