Skip to content

Bikeshed: design for .get_fragment() #11

Closed
@nmigen-issue-migration

Description

@nmigen-issue-migration

Issue by whitequark
Monday Dec 17, 2018 at 20:57 GMT
Originally opened as m-labs/nmigen#9


I know @jordens expressed in the past a desire to simplify the boilerplate around .get_fragment. Also, there is currently both Module.lower and Module.get_fragment (aliased to one another), which is confusing and unnecessary. Also#2, Migen has a Module.get_fragment() and combining Migen modules with nMigen modules gets even more confusing with that.

The design I see for the function currently named .get_fragment() is as follows:

  • There are 2 kinds of synthesizable entities in nMigen: fragments (which are directly synthesizable) and anything that has .get_fragment(platform) (which is iterated to a fixed point, i.e. a fragment, when a fragment is required).
  • Instances, memory ports, etc, are synthesizable. Which class they actually are is an implementation detail that is subject to change. (Instances are currently just fragments, memory ports are significantly more complex due to some mismatch between Yosys and Migen representation of ports, etc).
  • There is a Fragment.get(obj, platform) function that iterates an object to a fixed point with .get_fragment(platform) or fails in a nice way.

Modules are in a somewhat weird space here. Modules should be synthesizable so that you can replace:

sm = Module()
# ... operate on sm
m = Module()
m.submodules += sm

with:

class SubCircuit:
    def get_fragment(self, platform):
        m = Module()
        return m.lower(platform)
sm = SubCircuit()
m = Module()
m.submodules += sm

that is without having to do downstream changes after replacing a Module with a user class. This means that in principle you can directly return a module, like return m.

But this means two things:

  1. The actual get_fragment call for that module is delayed. The conversion of a module to a fragment is mostly (but not entirely) error-free, so delaying this call means some errors lose context. I think it might be more useful to make Module.get_fragment actually never fail, and permit return m.
  2. If a parent module directly calls get_fragment on a submodule, it gets a Module object with the DSL enabled, as opposed to a Fragment object. So it can potentially abuse the DSL that way. This isn't very likely so maybe we should just ignore it.

And finally, there is an important question of what to rename .get_fragment too. I don't want something like .build because it is ambiguous and prone to collisions. What about .synthesize?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions