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.
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
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 :
This correctly returns the inputs and outputs as follow
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.