Skip to content

Process meta information #114

Description

@el3ctrician

Hello,
I am working on a VHDL schematic viewer that lets you analyze and visualize a VHDL entity and see all connection to instances, proceesses etc. For that i wanted to figure out what are the "inputs" and "outputs" of a process as inputs defined as any signal that's "read" from withing the process and output is any signal that's driven by the process and for the following snippet code in vhdl

 process (clk)
    begin
        if rising_edge(clk) then
            if d = '0' then
                d <= g or s;
            else
                d <= g and s;
            end if;

        end if;
    end process;

Since i am using pyGHDL as a backend (i really want to move from it since i don't want/need GHDL) and with the help of AI i came up with the following code that parsers IIR nodes :

   def __get_iir_name(self, iir) -> str:
      ident = nodes.Get_Identifier(iir)
      return name_table.Get_Name_Ptr(ident)

  def __collect_names_from_iir(self, iir, names: set, visited=None):
      if visited is None:
          visited = set()
      if iir is None or iir == 0 or iir in visited:
          return
      visited.add(iir)

      kind = nodes.Get_Kind(iir)

      if kind == Iir_Kind.Simple_Name:
          names.add(self.__get_iir_name(iir))
          return

      if kind == Iir_Kind.Selected_Name:
          self.__collect_names_from_iir(nodes.Get_Prefix(iir), names, visited)
          return

      if kind in (Iir_Kind.Function_Call, Iir_Kind.Procedure_Call_Statement):
          assoc = nodes.Get_Parameter_Association_Chain(iir)
          while assoc != 0:
              actual = nodes.Get_Actual(assoc)
              self.__collect_names_from_iir(actual, names, visited)
              assoc = nodes.Get_Chain(assoc)
          return

      if kind in (
          Iir_Kind.And_Operator,
          Iir_Kind.Or_Operator,
          Iir_Kind.Nand_Operator,
          Iir_Kind.Nor_Operator,
          Iir_Kind.Xor_Operator,
          Iir_Kind.Xnor_Operator,
          Iir_Kind.Equality_Operator,
          Iir_Kind.Inequality_Operator,
          Iir_Kind.Less_Than_Operator,
          Iir_Kind.Greater_Than_Operator,
          Iir_Kind.Less_Than_Or_Equal_Operator,
          Iir_Kind.Greater_Than_Or_Equal_Operator,
          Iir_Kind.Addition_Operator,
          Iir_Kind.Substraction_Operator,
          Iir_Kind.Multiplication_Operator,
          Iir_Kind.Division_Operator,
          Iir_Kind.Concatenation_Operator,
      ):
          self.__collect_names_from_iir(nodes.Get_Left(iir), names, visited)
          self.__collect_names_from_iir(nodes.Get_Right(iir), names, visited)
          return

      if kind in (
          Iir_Kind.Not_Operator,
          Iir_Kind.Negation_Operator,
          Iir_Kind.Identity_Operator,
      ):
          self.__collect_names_from_iir(nodes.Get_Operand(iir), names, visited)
          return

      if kind in (Iir_Kind.Type_Conversion, Iir_Kind.Qualified_Expression):
          self.__collect_names_from_iir(nodes.Get_Expression(iir), names, visited)
          return

      if kind == Iir_Kind.Aggregate:
          assoc = nodes.Get_Association_Choices_Chain(iir)
          while assoc != 0:
              self.__collect_names_from_iir(nodes.Get_Associated_Expr(assoc), names, visited)
              assoc = nodes.Get_Chain(assoc)
          return

      if kind == Iir_Kind.Indexed_Name:
          self.__collect_names_from_iir(nodes.Get_Prefix(iir), names, visited)
          idx = nodes.Get_Index_List(iir)
          if idx != 0:
              item = nodes.Get_Nth_Element(idx, 0)
              i = 0
              while item != 0:
                  self.__collect_names_from_iir(item, names, visited)
                  i += 1
                  item = nodes.Get_Nth_Element(idx, i)
          return

      if kind == Iir_Kind.Slice_Name:
          self.__collect_names_from_iir(nodes.Get_Prefix(iir), names, visited)
          return

  def __walk_iir_statements(self, stmt_chain, inputs: set, outputs: set):
      stmt = stmt_chain
      while stmt != 0:
          kind = nodes.Get_Kind(stmt)

          if kind == Iir_Kind.Simple_Signal_Assignment_Statement:
              target_names = set()
              self.__collect_names_from_iir(nodes.Get_Target(stmt), target_names)
              outputs.update(target_names)
              waveform = nodes.Get_Waveform_Chain(stmt)
              while waveform != 0:
                  self.__collect_names_from_iir(nodes.Get_We_Value(waveform), inputs)
                  waveform = nodes.Get_Chain(waveform)

          elif kind == Iir_Kind.Variable_Assignment_Statement:
              target_names = set()
              self.__collect_names_from_iir(nodes.Get_Target(stmt), target_names)
              outputs.update(target_names)
              self.__collect_names_from_iir(nodes.Get_Expression(stmt), inputs)

          elif kind == Iir_Kind.If_Statement:
              self.__collect_names_from_iir(nodes.Get_Condition(stmt), inputs)
              self.__walk_iir_statements(nodes.Get_Sequential_Statement_Chain(stmt), inputs, outputs)
              clause = nodes.Get_Else_Clause(stmt)
              while clause != 0:
                  cond = nodes.Get_Condition(clause)
                  if cond != 0:
                      self.__collect_names_from_iir(cond, inputs)
                  self.__walk_iir_statements(nodes.Get_Sequential_Statement_Chain(clause), inputs, outputs)
                  clause = nodes.Get_Else_Clause(clause)

          elif kind == Iir_Kind.Case_Statement:
              self.__collect_names_from_iir(nodes.Get_Expression(stmt), inputs)
              alt = nodes.Get_Case_Statement_Alternative_Chain(stmt)
              while alt != 0:
                  self.__walk_iir_statements(nodes.Get_Associated_Chain(alt), inputs, outputs)
                  alt = nodes.Get_Chain(alt)

          elif kind in (Iir_Kind.For_Loop_Statement, Iir_Kind.While_Loop_Statement):
              self.__walk_iir_statements(nodes.Get_Sequential_Statement_Chain(stmt), inputs, outputs)

          stmt = nodes.Get_Chain(stmt)

  def analyze_process(self, process) -> dict:
      iir = process._iirNode
      inputs  = set()
      outputs = set()
      for sig in process.SensitivityList:
        inputs.add(sig.NormalizedIdentifier)
      # Statements
      stmt_chain = nodes.Get_Sequential_Statement_Chain(iir)
      self.__walk_iir_statements(stmt_chain, inputs, outputs)
      inputs = inputs - outputs
      return {"inputs": inputs, "outputs": outputs}

This correctly returns the inputs and outputs as follow

[DEBUG]:  Process: None, sysitivity list = [Name: 'clk']
[DEBUG]:    Analyzed : {'inputs': {'g', 's', 'clk'}, 'outputs': {'d'}} 

I would love to have this features directly in the pyVHDLModel since i can develop my tool entirely against the pyVHDLModel and then move to a different backend in the future. I am availabe to put in some effort, with some time limitation, into it.

Is it something that you see useful to be added to the model ? I would love to have some gudiance on understanding a bit more how pyVHDLModel handles that since my approach has been to look at the classes code and "guess" the information that i need in a very iterative process.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions