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

Hierarchical Flattening for Modules #86

Open
uduse opened this issue Jan 3, 2023 · 3 comments
Open

Hierarchical Flattening for Modules #86

uduse opened this issue Jan 3, 2023 · 3 comments

Comments

@uduse
Copy link
Collaborator

uduse commented Jan 3, 2023

Why we need it

Hierarchical information might not be needed for some use cases. For example, listing out all MOSes and compute their total area. It would be nice to have a functionality that flattens a module into a module with a single layer.

Specifications

(partial credit from @dan-fritchman)

  • The function takes a module and returns a new module.
  • All instances in the module are PrimitiveCalls or other types of leaf nodes.
  • Module ports are the ports from the original module.
  • Module signals are the signals from all levels and the ports from all non-root levels.
  • All primitive names and signal names are resolved to avoid name collisions.

Example

I have a small script to do this for simple cases (will PR later).

Source Module Vlsir

  modules {
  name: "src.hdl.Inverter"
  ports {
      signal: "vdd"
      direction: NONE
  }
  ports {
      signal: "vss"
      direction: NONE
  }
  ports {
      signal: "vin"
      direction: NONE
  }
  ports {
      signal: "vout"
      direction: NONE
  }
  signals {
      name: "vdd"
      width: 1
  }
  signals {
      name: "vss"
      width: 1
  }
  signals {
      name: "vin"
      width: 1
  }
  signals {
      name: "vout"
      width: 1
  }
  instances {
      name: "pmos"
      module {
      external {
          domain: "hdl21.primitives"
          name: "Mos"
      }
      }
      parameters {
      name: "tp"
      value {
          literal: "PMOS"
      }
      }
      connections {
      portname: "d"
      target {
          sig: "vout"
      }
      }
      connections {
      portname: "g"
      target {
          sig: "vin"
      }
      }
      connections {
      portname: "s"
      target {
          sig: "vdd"
      }
      }
  }
  instances {
      name: "nmos"
      module {
      external {
          domain: "hdl21.primitives"
          name: "Mos"
      }
      }
      parameters {
      name: "tp"
      value {
          literal: "NMOS"
      }
      }
      connections {
      portname: "d"
      target {
          sig: "vout"
      }
      }
      connections {
      portname: "g"
      target {
          sig: "vin"
      }
      }
      connections {
      portname: "s"
      target {
          sig: "vss"
      }
      }
  }
  }
  modules {
  name: "src.hdl.Buffer"
  ports {
      signal: "vdd"
      direction: NONE
  }
  ports {
      signal: "vss"
      direction: NONE
  }
  ports {
      signal: "vin"
      direction: NONE
  }
  ports {
      signal: "vout"
      direction: NONE
  }
  signals {
      name: "n0"
      width: 1
  }
  signals {
      name: "vdd"
      width: 1
  }
  signals {
      name: "vss"
      width: 1
  }
  signals {
      name: "vin"
      width: 1
  }
  signals {
      name: "vout"
      width: 1
  }
  instances {
      name: "inv_1"
      module {
      local: "src.hdl.Inverter"
      }
      connections {
      portname: "vdd"
      target {
          sig: "vdd"
      }
      }
      connections {
      portname: "vss"
      target {
          sig: "vss"
      }
      }
      connections {
      portname: "vin"
      target {
          sig: "vin"
      }
      }
      connections {
      portname: "vout"
      target {
          sig: "n0"
      }
      }
  }
  instances {
      name: "inv_2"
      module {
      local: "src.hdl.Inverter"
      }
      connections {
      portname: "vdd"
      target {
          sig: "vdd"
      }
      }
      connections {
      portname: "vss"
      target {
          sig: "vss"
      }
      }
      connections {
      portname: "vin"
      target {
          sig: "n0"
      }
      }
      connections {
      portname: "vout"
      target {
          sig: "vout"
      }
      }
  }
}

Flattened Module Vlsir

modules {
  name: "Buffer_flat"
  ports {
    signal: "vdd"
    direction: NONE
  }
  ports {
    signal: "vss"
    direction: NONE
  }
  ports {
    signal: "vin"
    direction: NONE
  }
  ports {
    signal: "vout"
    direction: NONE
  }
  signals {
    name: "n0"
    width: 1
  }
  signals {
    name: "vdd"
    width: 1
  }
  signals {
    name: "vss"
    width: 1
  }
  signals {
    name: "vin"
    width: 1
  }
  signals {
    name: "vout"
    width: 1
  }
  instances {
    name: "inv_1:pmos"
    module {
      external {
        domain: "hdl21.primitives"
        name: "Mos"
      }
    }
    parameters {
      name: "tp"
      value {
        literal: "PMOS"
      }
    }
    connections {
      portname: "d"
      target {
        sig: "n0"
      }
    }
    connections {
      portname: "g"
      target {
        sig: "vin"
      }
    }
    connections {
      portname: "s"
      target {
        sig: "vdd"
      }
    }
  }
  instances {
    name: "inv_1:nmos"
    module {
      external {
        domain: "hdl21.primitives"
        name: "Mos"
      }
    }
    parameters {
      name: "tp"
      value {
        literal: "NMOS"
      }
    }
    connections {
      portname: "d"
      target {
        sig: "n0"
      }
    }
    connections {
      portname: "g"
      target {
        sig: "vin"
      }
    }
    connections {
      portname: "s"
      target {
        sig: "vss"
      }
    }
  }
  instances {
    name: "inv_2:pmos"
    module {
      external {
        domain: "hdl21.primitives"
        name: "Mos"
      }
    }
    parameters {
      name: "tp"
      value {
        literal: "PMOS"
      }
    }
    connections {
      portname: "d"
      target {
        sig: "vout"
      }
    }
    connections {
      portname: "g"
      target {
        sig: "n0"
      }
    }
    connections {
      portname: "s"
      target {
        sig: "vdd"
      }
    }
  }
  instances {
    name: "inv_2:nmos"
    module {
      external {
        domain: "hdl21.primitives"
        name: "Mos"
      }
    }
    parameters {
      name: "tp"
      value {
        literal: "NMOS"
      }
    }
    connections {
      portname: "d"
      target {
        sig: "vout"
      }
    }
    connections {
      portname: "g"
      target {
        sig: "n0"
      }
    }
    connections {
      portname: "s"
      target {
        sig: "vss"
      }
    }
  }
}

@dan-fritchman
Copy link
Owner

This would be a welcome addition!
A few notes:


All instances in the module are PrimitiveCalls or other types of leaf nodes.

Particularly re the "other types of leaf nodes": Hdl21 has four Instantiable types -

Instantiable = Union[Module, ExternalModuleCall, GeneratorCall, PrimitiveCall]

I.e. those are the four kinds of things that can be the target of an hdl21.Instance.

Of those, two are "irreducible": primitives (PrimitiveCall) and external-modules (ExternalModuleCall). These would be the leaf-nodes when flattening.

Another (bonus!) feature would be adding the capacity for a "stop list" of Modules and/or GeneratorCalls, which when detected would just be turned into ExternalModuleCalls. Such things are common in popular "big EDA" software.


Module signals are the signals from all levels and the ports from all non-root levels.

I think that is potentially true, depending whether you'd want to include "floating" Signals, i.e. those which don't ultimately reach a leaf-level component.

Do Modules actually have these? Sure! They have all kinds of weird stuff, both intentionally and not. E.g. for:

  • Incompleteness. A Module may have an incomplete subsystem, and want to analyze the other, completed subsystems.
  • Bugs! Connections get screwed up, misnamed, misconnected, whatever.

Does it matter whether we do? Probably not; if the source-Module has floating Signals, I suppose it makes sense to just transfer them along to the flattened-Module. (Inside of a SPICE simulator, in contrast, you'd need to filter these out, or generally get a singular matrix due to them.)

@uduse
Copy link
Collaborator Author

uduse commented Jan 4, 2023

Where should this feature go in Hdl21 file structure? elab? Additionally, what role does Bundle play in this feature? (I have no idea how Bundle works...)

@dan-fritchman
Copy link
Owner

I think a package-level hdl21.flatten module, with a flatten() function, would be a good place.
And you shouldn't have to even notice Bundles are a thing, if you invoke elaboration before the flattening-work. So flatten() might look something like:

def flatten(m: Module) -> Module:
  elaborate(m)
  return flattening_stuff_youre_already_doing(m)

def flattening_stuff_youre_already_doing(m: Module) -> Module:
  # Ya know, the stuff you're already doing!

@uduse uduse mentioned this issue Jan 13, 2023
3 tasks
@uduse uduse linked a pull request Jan 24, 2023 that will close this issue
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants