Skip to content
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

Enumerated signals? #198

Closed
RobertBaruch opened this issue Sep 8, 2019 · 4 comments
Closed

Enumerated signals? #198

RobertBaruch opened this issue Sep 8, 2019 · 4 comments
Labels

Comments

@RobertBaruch
Copy link

What's the nMigen way of creating an enumerated signal, that is, a signal with a binary encoding whose values are named, possibly having some tie to Python Enums?

This seems to work:

from enum import Enum, unique
from nmigen import *
from nmigen.cli import main
from nmigen.asserts import *


@unique
class MCycle(Enum):
    NONE = 0
    M1 = 1
    MEM = 2
    IO = 3
    _next = 4

    @classmethod
    def signal(cls):
        return Signal.range(0, MCycle._next.value - 1)

    @property
    def const(self):
        return Const(self.value, MCycle.signal().shape())


class MCycler(Elaboratable):
    def __init__(self):
        self.mcycle = MCycle.signal()

    def ports(self):
        return [self.mcycle]

    def elaborate(self, platform):
        m = Module()
        m.d.pos += self.mcycle.eq(MCycle.M1.const)
        return m


if __name__ == "__main__":
    clk = Signal()
    rst = Signal()

    pos = ClockDomain()
    pos.clk = clk
    pos.rst = rst

    cycler = MCycler()

    m = Module()
    m.domains.pos = pos
    m.submodules.cycler = cycler

    main(m, ports=[clk, rst] + cycler.ports(), platform="formal")

However, the generated Verilog seems to use the name \$signal for mcycle.

Replacing self.mcycle = MCycle.signal() with self.mcycle = Signal.range(0, MCycle._next.value - 1) causes the generated Verilog to use mcycle as the name instead.

So:

  1. Why is that?
  2. Is there a more canonical way to create an enumerated signal?
@whitequark
Copy link
Contributor

However, the generated Verilog seems to use the name \$signal for mcycle.

You can use:

    @classmethod
    def signal(cls):
        return Signal.range(0, MCycle._next.value - 1, src_loc_at=1)

to tell nMigen which stack frame to get the variable name from.

You can also remove _next by using:

    @classmethod
    def signal(cls):
        return Signal.range(min(v.value for k,v in Enum.__members__.items()),
                            max(v.value for k,v in Enum.__members__.items()) + 1,
                            src_loc_at=1)

Otherwise, this code is idiomatic.

@whitequark
Copy link
Contributor

Incidentally, instead of

    clk = Signal()
    rst = Signal()

    pos = ClockDomain()
    pos.clk = clk
    pos.rst = rst

    # ...
 
    main(m, ports=[clk, rst] + cycler.ports(), platform="formal")

you should probably use

    pos = ClockDomain()

    cycler = MCycler()

    # ...

    main(m, ports=[pos.clk, pos.rst] + cycler.ports(), platform="formal")

@RobertBaruch
Copy link
Author

Ah, pos was left over from when I had two clock domains. I'll try your other suggestions!

@RobertBaruch
Copy link
Author

Works, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants