---------------------------------------------- -------------- ---------------------- -- -- -- OCARINA COMPONENTS -- -- -- -- OCARINA.EXPANDER.COMPONENTS.CONNECTIONS -- -- -- -- B o d y -- -- -- -- Copyright (C) 2005-2007, GET-Telecom Paris. -- -- -- -- Ocarina is free software; you can redistribute it and/or modify -- -- it under terms of the GNU General Public License as published by the -- -- Free Software Foundation; either version 2, or (at your option) any -- -- later version. Ocarina is distributed in the hope that it will be -- -- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -- -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -- -- Public License for more details. You should have received a copy of the -- -- GNU General Public License distributed with Ocarina; see file COPYING. -- -- If not, write to the Free Software Foundation, 51 Franklin Street, Fifth -- -- Floor, Boston, MA 02111-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- Ocarina is maintained by the Ocarina team -- -- (ocarina-users@listes.enst.fr) -- -- -- ------------------------------------------------------------------------------ with Ocarina.Nodes; with Ocarina.Nutils; with Ocarina.Entities; with Ocarina.Entities.Components; with Ocarina.Expander.Properties; package body Ocarina.Expander.Components.Connections is use Ocarina.Nodes; use Ocarina.Nutils; use Ocarina.Entities; use Ocarina.Entities.Components; use Ocarina.Expander.Properties; package ON renames Ocarina.Nodes; function Find_Connection_End (Component_Instance : node_id; Connection_End : node_id) return node_id; -- Find the entity (feature, subcomponent, etc.) instance pointed -- by the connection end. ------------------------- -- Find_Connection_End -- ------------------------- function Find_Connection_End (Component_Instance : node_id; Connection_End : node_id) return node_id is pragma assert (Kind (Component_Instance) = k_component_instance and then Kind (Connection_End) = k_entity_reference); Entity : node_id; Entity_Path : node_id; begin if No (First_Node (Path (Connection_End))) then Entity_Path := No_Node; else Entity_Path := New_Node (k_entity_reference_instance, Loc (Connection_End)); case Kind (Corresponding_Entity (Item (First_Node (Path (Connection_End))))) is when k_port_spec | k_subcomponent_access | k_port_group_spec | k_parameter | k_subprogram_spec => Entity := Get_First_Homonym (Features (Component_Instance), Name (Item (First_Node (Path (Connection_End))))); when k_subcomponent => Entity := Get_First_Homonym (Subcomponents (Component_Instance), Name (Item (First_Node (Path (Connection_End))))); when k_subprogram_call => if not Is_Empty (Calls (Component_Instance)) then declare List_Node : node_id := First_Node (Calls (Component_Instance)); begin while Present (List_Node) loop Entity := Get_First_Homonym (Subprogram_Calls (List_Node), Name (Item (First_Node (Path (Connection_End))))); exit when Present (Entity); List_Node := Next_Node (List_Node); end loop; end; else Entity := No_Node; end if; when others => raise Program_Error; end case; if Present (Entity) then -- Add the pointed entity into the entity instance path Add_Path_Element_To_Entity_Reference (Entity_Path, Entity); if Present (Next_Node (First_Node (Path (Connection_End)))) then case Kind (Corresponding_Entity (Item (First_Node (Path (Connection_End))))) is when k_subcomponent_access => Entity := No_Node; -- XXX we have to find the feature instance of the -- corresponding subcomponent instance. when k_port_group_spec => Entity := Get_First_Homonym (Features (Entity), Name (Item (Next_Node (First_Node (Path (Connection_End)))))); when k_subcomponent | k_subprogram_call => Entity := Get_First_Homonym (Features (Corresponding_Instance (Entity)), Name (Item (Next_Node (First_Node (Path (Connection_End)))))); when others => raise Program_Error; end case; -- Add the pointed entity into the entity instance -- path. Add_Path_Element_To_Entity_Reference (Entity_Path, Entity); end if; end if; end if; return Entity_Path; end Find_Connection_End; ----------------------- -- Expand_Connection -- ----------------------- function Expand_Connection (Instance_Root : node_id; Component_Instance : node_id; Connection : node_id) return node_id is pragma assert (Kind (Instance_Root) = k_architecture_instance and then Kind (Connection) = k_connection); New_Instance : constant node_id := New_Node (k_connection_instance, Loc (Connection)); Connection_Src : node_id; Connection_Dst : node_id; Success : Boolean; begin Set_Corresponding_Declaration (New_Instance, Connection); Set_Parent_Component (New_Instance, Component_Instance); Set_Identifier (New_Instance, Duplicate_Identifier (Identifier (Connection))); if Identifier (New_Instance) /= No_Node then Set_Corresponding_Entity (Identifier (New_Instance), New_Instance); end if; -- Set the connection ends and link them to the the connection -- instance. Connection_Src := Find_Connection_End (Component_Instance, Source (Connection)); Set_Source (New_Instance, Connection_Src); Connection_Dst := Find_Connection_End (Component_Instance, Destination (Connection)); Set_Destination (New_Instance, Connection_Dst); -- Make the connection ends aware of themselves and of the -- connection in which they are involved. Append_Node_To_List (Make_Node_Container (Item (Last_Node (Path (Connection_Dst))), New_Instance), Destinations (Item (Last_Node (Path (Connection_Src))))); Append_Node_To_List (Make_Node_Container (Item (Last_Node (Path (Connection_Src))), New_Instance), Sources (Item (Last_Node (Path (Connection_Dst))))); -- Set the connection type Set_Associated_Type (New_Instance, No_Node); -- Apply the properties of the connection to the connection -- instance. Success := Apply_Properties (Instance_Root, New_Instance, Ocarina.Nodes.Properties (Connection)); if not Success then return No_Node; end if; return New_Instance; end Expand_Connection; --------------------------------- -- Compute_Virtual_Connections -- --------------------------------- function Compute_Virtual_Connections (Instance_Root : node_id; Component_Instance : node_id; Source_Entity : node_id; Virtual_Cnx : node_id) return Boolean is pragma assert (Kind (Instance_Root) = k_architecture_instance and then Kind (Component_Instance) = k_component_instance and then (Kind (Source_Entity) = k_port_spec_instance or else Kind (Source_Entity) = k_feature_instance or else Kind (Source_Entity) = k_subprogram_spec_instance or else Kind (Source_Entity) = k_parameter_instance or else Kind (Source_Entity) = k_subcomponent_access_instance or else Kind (Source_Entity) = k_subcomponent_instance)); pragma assert (No (Virtual_Cnx) or else Kind (Virtual_Cnx) = k_virtual_connection); List_Node : node_id; List_Node2 : node_id; New_Cnx : node_id; Container : node_id; First_Cnx : Boolean := True; Success : Boolean := True; begin if not Is_Empty (ON.Connections (Component_Instance)) then List_Node := First_Node (ON.Connections (Component_Instance)); while Present (List_Node) loop if Get_Referenced_Entity (Source (List_Node)) = Source_Entity then if No (Virtual_Cnx) then -- If there is no existing virtual connection, then -- we are at a starting point; we create a new -- virtual connection. New_Cnx := New_Node (k_virtual_connection, Loc (List_Node)); Set_Associated_Type (New_Cnx, Associated_Type (List_Node)); Set_Source (New_Cnx, Get_Referenced_Entity (Source (List_Node))); Set_Destination (New_Cnx, Get_Referenced_Entity (Destination (List_Node))); Append_Node_To_List (New_Cnx, Virtual_Connections (Instance_Root)); Container := New_Node (k_node_container, Loc (List_Node)); Set_Item (Container, List_Node); Set_Connection_Instances (New_Cnx, New_List (k_list_id, Loc (New_Cnx))); Append_Node_To_List (Container, Connection_Instances (New_Cnx)); elsif First_Cnx then -- Else, we are completing a virtual -- connection. For the first new connection, we -- simply append it to the list of connections -- within the existing virtual connection New_Cnx := Virtual_Cnx; Container := New_Node (k_node_container, Loc (List_Node)); Set_Item (Container, List_Node); Append_Node_To_List (Container, Connection_Instances (New_Cnx)); Set_Destination (New_Cnx, Get_Referenced_Entity (Destination (List_Node))); First_Cnx := False; else -- For other connections, we have to create a new -- virtual connection. New_Cnx := New_Node (k_virtual_connection, Loc (Virtual_Cnx)); Set_Associated_Type (New_Cnx, Associated_Type (Virtual_Cnx)); Set_Source (New_Cnx, Source (Virtual_Cnx)); Set_Destination (New_Cnx, Get_Referenced_Entity (Destination (List_Node))); Append_Node_To_List (New_Cnx, Virtual_Connections (Instance_Root)); List_Node2 := First_Node (Connection_Instances (Virtual_Cnx)); while Present (List_Node2) loop Container := New_Node (k_node_container, Loc (List_Node2)); Set_Item (Container, Item (List_Node2)); Append_Node_To_List (Container, Connection_Instances (New_Cnx)); List_Node2 := Next_Node (List_Node2); end loop; Container := New_Node (k_node_container, Loc (List_Node)); Set_Item (Container, List_Node); Set_Connection_Instances (New_Cnx, New_List (k_list_id, Loc (New_Cnx))); Append_Node_To_List (Container, Connection_Instances (New_Cnx)); end if; if Parent_Component (Get_Referenced_Entity (Destination (List_Node))) = Component_Instance then -- The destination is inside the current component; -- following the connections will lead us outside -- of the component. Success := Compute_Virtual_Connections (Instance_Root => Instance_Root, Component_Instance => Parent_Component (Parent_Subcomponent (Component_Instance)), Source_Entity => Get_Referenced_Entity (Destination (List_Node)), Virtual_Cnx => New_Cnx) and then Success; elsif Get_Category_Of_Component (Parent_Component (Get_Referenced_Entity (Destination (List_Node)))) = cc_thread then -- We reached a feature of a thread. This is the -- end of the virtual connection. Set_Destination (New_Cnx, Get_Referenced_Entity (Destination (List_Node))); Success := True; else -- we reached a subcomponent which is not a thread; -- we follow the connections further. Success := Compute_Virtual_Connections (Instance_Root => Instance_Root, Component_Instance => Parent_Component (Get_Referenced_Entity (Destination (List_Node))), Source_Entity => Get_Referenced_Entity (Destination (List_Node)), Virtual_Cnx => New_Cnx) and then Success; end if; end if; List_Node := Next_Node (List_Node); end loop; end if; return True; end Compute_Virtual_Connections; end Ocarina.Expander.Components.Connections;