----------------------------------------------------------- --------------------- -- -- -- OCARINA COMPONENTS -- -- -- -- G A I A . P N -- -- -- -- B o d y -- -- -- -- Copyright (C) 2006-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 Namet; with Gaia.Utils; with Gaia.Processor.Nodes; with Gaia.Processor.Nodes.Utils; with Gaia.Pn.Nodes; with Gaia.Pn.Nutils; with Ocarina.AADL_Values; with Gaia.Pn.Debug; use Gaia.Pn.Debug; package body Gaia.Pn is package GN renames Gaia.Processor.Nodes; package GNU renames Gaia.Processor.Nodes.Utils; package GPN renames Gaia.Pn.Nodes; package GPNU renames Gaia.Pn.Nutils; package OAV renames Ocarina.AADL_Values; use Types; use Namet; use GN; use GPN; use GPNU; -- The space between the nearests two PN nodes Horizontal_Space : constant Natural := 60; Vertical_Space : constant Natural := 90; procedure Process_Declaration (Decl, Parent, Root : Types.node_id; L : in out node_location); procedure Process_Namespace (Gaia_Namespace, Parent, Root : Types.node_id; L : in out node_location); procedure Connect_Namespaces (Gaia_Namespace, Root_Node : Types.node_id); procedure Process_Namespace_Data (Gaia_Data_Def, Root, Namespace : node_id); procedure Process_Root_Node (Gaia_Root, Parent : Types.node_id; L : in out node_location); procedure Connect_Root_Nodes (Gaia_Root, Root_Node : node_id); procedure Process_Thread (Gaia_Thread, Parent : Types.node_id; L : in out node_location); procedure Connect_To_Others_Threads (Gaia_Port, Root_Node : Types.node_id); procedure Process_Port (Gaia_Port, Parent : Types.node_id; Out_Cpt : in out Integer); procedure Connect_Threads (Gaia_Thread, Root_Node : Types.node_id); procedure Process_Process (Gaia_Process, Parent : Types.node_id; L : in out node_location); procedure Connect_Process (Gaia_Process, Root_Node : node_id); procedure Process_Statement (Decl, Parent, Thread : Types.node_id; L : in out node_location); procedure Process_Call_Sequence (Gaia_Sequence, Parent, Thread : Types.node_id; L : in out node_location); procedure Process_Call (Gaia_Call, Parent, Thread : Types.node_id; L : in out node_location); procedure Inc_X (L : in out node_location); procedure Inc_Y (L : in out node_location); procedure Decr_Y (L : in out node_location); pragma unreferenced (Decr_Y); procedure Decr_X (L : in out node_location); ------------ -- Decr_Y -- ------------ procedure Decr_Y (L : in out node_location) is begin L.Y := L.Y - Vertical_Space; end Decr_Y; ------------ -- Decr_X -- ------------ procedure Decr_X (L : in out node_location) is begin L.X := L.X - Horizontal_Space; end Decr_X; ----------- -- Inc_X -- ----------- procedure Inc_X (L : in out node_location) is begin L.X := L.X + Horizontal_Space; end Inc_X; ----------- -- Inc_Y -- ----------- procedure Inc_Y (L : in out node_location) is begin L.Y := L.Y + Vertical_Space; end Inc_Y; ------------------ -- Process_Call -- ------------------ procedure Process_Call (Gaia_Call, Parent, Thread : Types.node_id; L : in out node_location) is pragma assert (Gaia_Call /= No_Node and then GN.Kind (Gaia_Call) = GN.k_subprogram_call); Call_Node : node_id; Param : node_id; Func_In : node_id; Func_Out : node_id; Connect : node_id; List_Node : node_id; Name : name_id; Ctl : node_id; Connect_1 : node_id; Connect_2 : node_id; Program : node_id; Choose, Join : node_id; Current_Pos : node_location; Extrema : node_location; Tmp_Pos : node_location; Cnx_Base : node_location; Thread_Reset : node_id; Func_Domain : constant list_id := New_List (k_list_id); N : node_id; Color : node_id; Dest_Color : node_id; Seq_Calls : Integer := 0; begin Call_Node := GPNU.Make_Fonctionnal_Entity; Name := GN.Name (GN.Identifier (GN.Scoped_Name (Gaia_Call))); GPN.Set_Identifier (Call_Node, GPNU.Make_Identifier (Call_Node, GN.Name (GN.Identifier (Gaia_Call)))); GPN.Set_Scoped_Name (Call_Node, GPNU.Make_Scoped_Name (Call_Node, Parent, Name)); Current_Pos.X := L.X; Current_Pos.Y := L.Y; -- We create transitions in order to modelize fonction execution -- We create places for control flow -- Input control flow Set_Str_To_Name_Buffer ("in_ctl"); Name := Name_Find; Ctl := GPNU.Make_Place_Declaration (Name, Current_Pos); Inc_X (Current_Pos); Add_Domain_To_Node (Control_Color, Ctl); GPN.Set_Scoped_Name (Ctl, GPNU.Make_Scoped_Name (Ctl, Call_Node, Name)); GPNU.Append_Node_To_List (Ctl, GPN.Places (Call_Node)); Set_Str_To_Name_Buffer ("func_enter"); Name := Name_Find; Func_In := GPNU.Make_Transition_Declaration (Name, Current_Pos); Inc_X (Current_Pos); GPN.Set_Scoped_Name (Func_In, GPNU.Make_Scoped_Name (Func_In, Call_Node, Name)); GPNU.Append_Node_To_List (Func_In, GPN.Transitions (Call_Node)); Connect := Make_Connection_Statement (Ctl, Func_In, True); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); Set_Begin_Node (Call_Node, Ctl); -- We create the places for subprogram call parameters -- input parameters only if GN.Parameters (Gaia_Call) /= No_List then List_Node := GN.First_Node (GN.Parameters (Gaia_Call)); Tmp_Pos.X := Current_Pos.X; Tmp_Pos.Y := Current_Pos.Y; Decr_X (Tmp_Pos); Decr_X (Tmp_Pos); Inc_Y (Tmp_Pos); while Present (List_Node) loop if GN.Is_In (List_Node) then Name := GN.Name (GN.Identifier (GN.Scoped_Name (List_Node))); Param := GPNU.Make_Place_Declaration (Name, Tmp_Pos); Inc_Y (Tmp_Pos); Add_Domain_To_Node (GN.Backend_Node (GN.Identifier (GN.Reference (Type_Spec (List_Node)))), Param); if GN.Backend_Node (GN.Identifier (List_Node)) = No_Node then GN.Set_Backend_Node (GN.Identifier (List_Node), Make_Fifo_Extremities (Thread)); end if; GPN.Set_Port_Reference (GN.Backend_Node (GN.Identifier (List_Node)), Param); GPN.Set_Scoped_Name (Param, GPNU.Make_Scoped_Name (Param, Call_Node, Name)); GPNU.Append_Node_To_List (Param, GPN.Places (Call_Node)); Connect := Make_Connection_Statement (Param, Func_In, True); Add_Domain_To_Node (GN.Backend_Node (GN.Identifier (GN.Reference (Type_Spec (List_Node)))), Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); end if; -- We keep a trace of parameters types Add_Domain_To_List (GN.Backend_Node (GN.Identifier (GN.Reference (Type_Spec (List_Node)))), Func_Domain); List_Node := GN.Next_Node (List_Node); end loop; end if; Extrema.Y := Tmp_Pos.Y; Program := GN.Corresponding_Subprogram (Gaia_Call); -- We process call sequences if not Is_Empty (GPN.Sub_Components (Call_Node)) then -- Create the subprogram.choose place Set_Str_To_Name_Buffer ("choose"); Name := Name_Find; Choose := GPNU.Make_Place_Declaration (Name, Current_Pos); Inc_X (Current_Pos); Add_Domain_To_Node (Control_Color, Choose); GPN.Set_Scoped_Name (Choose, GPNU.Make_Scoped_Name (Choose, Call_Node, Name)); GPNU.Append_Node_To_List (Choose, GPN.Places (Call_Node)); Tmp_Pos.X := Current_Pos.X; Tmp_Pos.Y := Current_Pos.Y; if GN.Call_Sequences (Program) /= No_List then List_Node := GN.First_Node (GN.Call_Sequences (Program)); while Present (List_Node) loop Process_Statement (List_Node, Call_Node, Thread, Tmp_Pos); Inc_Y (Tmp_Pos); -- update extrema Extrema.Y := Natural'max (Extrema.Y, Tmp_Pos.Y); Extrema.X := Natural'max (Extrema.X, Tmp_Pos.X); -- re-align on X axis for parallelism Tmp_Pos.X := Current_Pos.X; List_Node := GN.Next_Node (List_Node); end loop; end if; -- Update Current_Pos Current_Pos.X := Extrema.X; -- Create the thread.join place Set_Str_To_Name_Buffer ("join"); Name := Name_Find; Join := GPNU.Make_Place_Declaration (Name, Current_Pos); Inc_X (Current_Pos); Add_Domain_To_Node (Control_Color, Join); GPN.Set_Scoped_Name (Join, GPNU.Make_Scoped_Name (Join, Call_Node, Name)); GPNU.Append_Node_To_List (Join, GPN.Places (Call_Node)); Connect := Make_Connection_Statement (Func_In, Choose, False); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); -- Connect call sequences List_Node := GPN.First_Node (GPN.Sub_Components (Call_Node)); while Present (List_Node) loop -- Call sequences counter Seq_Calls := Seq_Calls + 1; Connect := Make_Connection_Statement (Choose, Begin_Node (List_Node), True); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); Connect := Make_Connection_Statement (End_Node (List_Node), Join, False); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); List_Node := GPN.Next_Node (List_Node); end loop; if Seq_Calls >= 2 then -- We have non-deterministic sequences calls -- so we set a call to an optional behavioural definition Set_Include_Call (Call_Node, Make_Include_Call ("UD", Gaia_Call)); end if; Set_Str_To_Name_Buffer ("func_leave"); Name := Name_Find; Func_Out := GPNU.Make_Transition_Declaration (Name, Current_Pos); Inc_X (Current_Pos); GPN.Set_Scoped_Name (Func_Out, GPNU.Make_Scoped_Name (Func_Out, Call_Node, Name)); GPNU.Append_Node_To_List (Func_Out, GPN.Transitions (Call_Node)); Connect := Make_Connection_Statement (Join, Func_Out, True); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); else -- Create a single place to model function execution time -- and set a call to an optional behavioural definition Set_Include_Call (Call_Node, Make_Include_Call (Gaia_Call, Corresponding_Subprogram (Gaia_Call))); Set_Str_To_Name_Buffer ("exec"); Name := Name_Find; Ctl := GPNU.Make_Place_Declaration (Name, Current_Pos); Inc_X (Current_Pos); GPN.Set_Scoped_Name (Ctl, GPNU.Make_Scoped_Name (Ctl, Call_Node, Name)); GPNU.Append_Node_To_List (Ctl, GPN.Places (Call_Node)); Connect := Make_Connection_Statement (Func_In, Ctl, False); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); Set_Str_To_Name_Buffer ("func_leave"); Name := Name_Find; Func_Out := GPNU.Make_Transition_Declaration (Name, Current_Pos); Inc_X (Current_Pos); GPN.Set_Scoped_Name (Func_Out, GPNU.Make_Scoped_Name (Func_Out, Call_Node, Name)); GPNU.Append_Node_To_List (Func_Out, GPN.Transitions (Call_Node)); Connect_2 := Make_Connection_Statement (Ctl, Func_Out, True); GPNU.Append_Node_To_List (Connect_2, GPN.Connections (Call_Node)); -- The domain of an exec node contains both control, input -- and output type. if not GPNU.Is_Empty (Func_Domain) then N := GPN.First_Node (Func_Domain); while N /= No_Node loop Add_Domain_To_Node (Refered_Node (N), Ctl); Add_Domain_To_Node (Refered_Node (N), Connect); Add_Domain_To_Node (Refered_Node (N), Connect_2); N := GPN.Next_Node (N); end loop; end if; Add_Domain_To_Node (Control_Color, Ctl); Add_Domain_To_Node (Control_Color, Connect); Add_Domain_To_Node (Control_Color, Connect_2); end if; -- Then we proceed output parameters if GN.Parameters (Gaia_Call) /= No_List then List_Node := GN.First_Node (GN.Parameters (Gaia_Call)); Tmp_Pos := Current_Pos; Tmp_Pos := Current_Pos; Inc_Y (Tmp_Pos); if Full_Naming_Policy then Thread_Reset := Reset_Transition (Thread); else Thread_Reset := Current_Thread; end if; while Present (List_Node) loop if GN.Is_Out (List_Node) then Color := GN.Backend_Node (GN.Identifier (GN.Reference (Type_Spec (List_Node)))); Name := GN.Name (GN.Identifier (GN.Scoped_Name (List_Node))); Param := GPNU.Make_Place_Declaration (Name, Tmp_Pos); Inc_Y (Tmp_Pos); Add_Domain_To_Node (Color, Param); if GN.Backend_Node (GN.Identifier (List_Node)) = No_Node then GN.Set_Backend_Node (GN.Identifier (List_Node), Make_Fifo_Extremities (Thread)); end if; GPN.Set_Port_Reference (GN.Backend_Node (GN.Identifier (List_Node)), Param); GPN.Set_Scoped_Name (Param, GPNU.Make_Scoped_Name (Param, Call_Node, Name)); GPNU.Append_Node_To_List (Param, GPN.Places (Call_Node)); -- We connect the parameter with the function trigger Connect := Make_Connection_Statement (Func_Out, Param, False); Add_Domain_To_Node (Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); -- We link back the out parameter to the trigger so that hit -- value could be re-read and it could update hit own value -- whenever the function is triggered. Connect := Make_Connection_Statement (Param, Func_Out, True); Add_Domain_To_Node (Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); -- We double-link the parameter to the related thread so -- that it could be reset to defaut value when thread itself -- is reset. Connect := Make_Connection_Statement (Param, Thread_Reset, True); Add_Domain_To_Node (Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); Connect := Make_Connection_Statement (Thread_Reset, Param, False); Add_Token_Value_To_Arc (Connect, Invalid_Color_Obj, Color); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); -- Set a default value which will inhibate connexion triggering Add_Token_To_Place (Param, Invalid_Color_Obj, Color); end if; List_Node := GN.Next_Node (List_Node); end loop; end if; Extrema.Y := Natural'max (Extrema.Y, Tmp_Pos.Y); -- We make links for subprogram's connections if not GNU.Is_Empty (GN.Connections (Program)) then List_Node := GN.First_Node (GN.Connections (Program)); while Present (List_Node) loop Color := GN.Backend_Node (GN.Identifier (GN.Reference (Type_Spec (GN.Source (List_Node))))); Dest_Color := GN.Backend_Node (GN.Identifier (GN.Reference (Type_Spec (GN.Destination (List_Node))))); -- Create the connection (transition) Inc_Y (Extrema); Cnx_Base.X := L.X; Cnx_Base.Y := Extrema.Y; Inc_X (Cnx_Base); Name := GN.Name (GN.Identifier (GN.Scoped_Name (List_Node))); Connect := GPNU.Make_Transition_Declaration (Name, Cnx_Base); Inc_X (Cnx_Base); GPN.Set_Scoped_Name (Connect, GPNU.Make_Scoped_Name (Connect, Call_Node, Name)); -- Create a link from source to Connect (connection) Connect_1 := Make_Connection_Statement (Port_Reference (GN.Backend_Node (GN.Identifier (GN.Source ((List_Node))))), Connect, True); Add_Domain_To_Node (Color, Connect_1); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Call_Node)); -- Create a link from Connect (connection) to destination Connect_2 := Make_Connection_Statement (Connect, Port_Reference (GN.Backend_Node (GN.Identifier (GN.Destination ((List_Node))))), False); Add_Domain_To_Node (Dest_Color, Connect_2); GPNU.Append_Node_To_List (Connect_2, GPN.Connections (Call_Node)); -- List_Node's source always refers to a parameter -- so we link back the source node Connect_1 := Make_Connection_Statement (Connect, Port_Reference (GN.Backend_Node (GN.Identifier (GN.Source ((List_Node))))), False); Add_Domain_To_Node (Color, Connect_1); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Call_Node)); -- Put a guard on Connection transition -- so that the connection couldn't read paramater initial -- default value. Make_Guard (Connect, Color, Color_Variable (Color), Invalid_Color_Obj); GPNU.Append_Node_To_List (Connect, GPN.Transitions (Call_Node)); List_Node := GN.Next_Node (List_Node); end loop; Extrema.X := Natural'max (Extrema.X, Cnx_Base.X); end if; -- Output control flow Set_Str_To_Name_Buffer ("out_ctl"); Name := Name_Find; Ctl := GPNU.Make_Place_Declaration (Name, Current_Pos); Inc_X (Current_Pos); Add_Domain_To_Node (Control_Color, Ctl); GPN.Set_Scoped_Name (Ctl, GPNU.Make_Scoped_Name (Ctl, Call_Node, Name)); GPNU.Append_Node_To_List (Ctl, GPN.Places (Call_Node)); Connect := Make_Connection_Statement (Func_Out, Ctl, False); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Call_Node)); Set_End_Node (Call_Node, Ctl); -- We give back max X and Y L.X := Current_Pos.X; L.Y := Extrema.Y; GPNU.Append_Node_To_List (Call_Node, GPN.Sub_Components (Parent)); end Process_Call; --------------------------- -- Process_Call_Sequence -- --------------------------- procedure Process_Call_Sequence (Gaia_Sequence, Parent, Thread : Types.node_id; L : in out node_location) is pragma assert (Gaia_Sequence /= No_Node and then GN.Kind (Gaia_Sequence) = GN.k_call_sequence); Sequence : node_id; List_Node : node_id; Fusion : node_id; Seq_In : node_id; Seq_Out : node_id; Connect : node_id; Name : name_id; C : node_id; Prev : node_id := No_Node; P : node_location; Extrema : node_location; begin Sequence := GPNU.Make_Fonctionnal_Entity; GPN.Set_Identifier (Sequence, GPNU.Make_Identifier (Sequence, GN.Name (GN.Identifier (Gaia_Sequence)))); GPN.Set_Scoped_Name (Sequence, GPNU.Make_Scoped_Name (Sequence, Parent, GN.Name (GN.Identifier (GN.Scoped_Name (Gaia_Sequence))))); Extrema.X := L.X; Extrema.Y := L.Y; P.X := L.X; P.Y := L.Y; -- Begin control flow node Set_Str_To_Name_Buffer ("begin"); Name := Name_Find; Seq_In := GPNU.Make_Transition_Declaration (Name, P); GPN.Set_Scoped_Name (Seq_In, GPNU.Make_Scoped_Name (Seq_In, Sequence, Name)); GPNU.Append_Node_To_List (Seq_In, GPN.Transitions (Sequence)); Inc_X (P); -- Process each call of the sequence if GN.Statements (Gaia_Sequence) /= No_List then List_Node := GN.First_Node (GN.Statements (Gaia_Sequence)); while Present (List_Node) loop Process_Call (List_Node, Sequence, Thread, P); -- update extrema Extrema.Y := Natural'max (Extrema.Y, P.Y); Extrema.X := Natural'max (Extrema.X, P.X); -- we re-align on Y axis for sequenciality P.Y := L.Y; if Prev /= No_Node then C := GPN.Last_Node (GPN.Sub_Components (Sequence)); -- We create a transition in order to link to following -- calls Set_Str_To_Name_Buffer (Get_Name_String (GPN.Name (GPN.Identifier (GPN.Scoped_Name ((Prev)))))); Add_Str_To_Name_Buffer ("_next"); Name := Name_Find; Fusion := GPNU.Make_Transition_Declaration (Name, P); Inc_X (P); GPN.Set_Scoped_Name (Fusion, GPNU.Make_Scoped_Name (Fusion, Sequence, Name)); GPNU.Append_Node_To_List (Fusion, GPN.Transitions (Sequence)); Connect := Make_Connection_Statement (End_Node (Prev), Fusion, True); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Sequence)); Connect := Make_Connection_Statement (Fusion, Begin_Node (C), False); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Sequence)); Prev := C; else Prev := GPN.Last_Node (GPN.Sub_Components (Sequence)); end if; List_Node := GN.Next_Node (List_Node); end loop; -- Begin control flow node Set_Str_To_Name_Buffer ("end"); Name := Name_Find; Seq_Out := GPNU.Make_Transition_Declaration (Name, P); Inc_X (P); GPN.Set_Scoped_Name (Seq_Out, GPNU.Make_Scoped_Name (Seq_Out, Sequence, Name)); GPNU.Append_Node_To_List (Seq_Out, GPN.Transitions (Sequence)); -- Connect control flow nodes Connect := Make_Connection_Statement (Seq_In, GPN.Begin_Node (GPN.First_Node (GPN.Sub_Components (Sequence))), False); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Sequence)); Connect := Make_Connection_Statement (GPN.End_Node (GPN.Last_Node (GPN.Sub_Components (Sequence))), Seq_Out, True); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Sequence)); GPN.Set_Begin_Node (Sequence, Seq_In); GPN.Set_End_Node (Sequence, Seq_Out); else GPN.Set_Begin_Node (Sequence, No_Node); GPN.Set_End_Node (Sequence, No_Node); end if; L.X := P.X; L.Y := Extrema.Y; GPNU.Append_Node_To_List (Sequence, GPN.Sub_Components (Parent)); end Process_Call_Sequence; ----------------------- -- Process_Statement -- ----------------------- procedure Process_Statement (Decl, Parent, Thread : Types.node_id; L : in out node_location) is begin case GN.Kind (Decl) is when GN.k_call_sequence => Process_Call_Sequence (Decl, Parent, Thread, L); when GN.k_subprogram_call => Process_Call (Decl, Parent, Thread, L); when others => raise Program_Error; end case; end Process_Statement; ------------------ -- Process_Port -- ------------------ procedure Process_Port (Gaia_Port, Parent : Types.node_id; Out_Cpt : in out Integer) is pragma assert (Gaia_Port /= No_Node and then GN.Kind (Gaia_Port) = GN.k_port); Port : node_id; Name : name_id; Scoped : node_id; Fifo : node_id; Ack : node_id; Cnx : node_id; Connect : node_id; Color : node_id; begin -- This procedure will build the port and, if needed, extend it as -- A fifo buffer. if GN.Backend_Node (GN.Identifier (Gaia_Port)) = No_Node then GN.Set_Backend_Node (GN.Identifier (Gaia_Port), Make_Fifo_Extremities (Parent)); end if; Fifo := GN.Backend_Node (GN.Identifier (Gaia_Port)); Color := GN.Backend_Node (GN.Identifier (GN.Reference (Type_Spec (Gaia_Port)))); Name := GN.Name (GN.Identifier (GN.Scoped_Name (Gaia_Port))); Port := GPNU.Make_Place_Declaration (Name); Scoped := GPNU.Make_Scoped_Name (Port, Parent, Name); Add_Domain_To_Node (Color, Port); GPN.Set_Scoped_Name (Port, Scoped); GPNU.Append_Node_To_List (Port, GPN.Places (Parent)); GPNU.Append_Node_To_Fifo (Port, Fifo); Set_Port_Reference (GN.Backend_Node (GN.Identifier (Gaia_Port)), Port); if GN.Is_In (Gaia_Port) then Add_Domain_To_Node (Control_Color, Port); -- We create a place to send back an acknowledgment to sender thread Set_Str_To_Name_Buffer ("ack"); Name := Name_Find; Ack := GPNU.Make_Place_Declaration (Name); GPN.Set_Scoped_Name (Ack, GPNU.Make_Scoped_Name (Ack, Port, Name)); Add_Domain_To_Node (Control_Color, Ack); GPNU.Append_Node_To_Fifo (Ack, Fifo); GPNU.Append_Node_To_List (Ack, GPN.Places (Parent)); Set_Ack_Place (Fifo, Ack); -- We create a connexion Set_Str_To_Name_Buffer ("push"); Name := Name_Find; Cnx := GPNU.Make_Transition_Declaration (Name); GPN.Set_Scoped_Name (Cnx, GPNU.Make_Scoped_Name (Cnx, Port, Name)); GPNU.Append_Node_To_List (Cnx, GPN.Transitions (Parent)); GPNU.Append_Node_To_Fifo (Cnx, Fifo); -- We link them Connect := Make_Connection_Statement (Cnx, Port, False); Add_Domain_To_Node (Color, Connect); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Parent)); GPN.Set_Push_Transition (Fifo, Cnx); else -- Increment the out port's counter Out_Cpt := Out_Cpt + 1; end if; GPNU.Append_Node_To_List (Fifo, GPN.Fifos (Parent)); GN.Set_Backend_Node (GN.Identifier (Gaia_Port), Fifo); end Process_Port; ------------------------------- -- Connect_To_Others_Threads -- ------------------------------- procedure Connect_To_Others_Threads (Gaia_Port, Root_Node : Types.node_id) is use OAV; use Ocarina.Nodes; pragma assert (Gaia_Port /= No_Node and then GN.Kind (Gaia_Port) = GN.k_port); Dest_Gaia : node_id; Dest : node_id; Connect : node_id; Src_Trans : node_id; Src : node_id; P : node_location; Name : name_id; Diff : node_id; Pl : node_id; First_Iter : Boolean := True; Val : Integer; begin if GN.Is_Out (Gaia_Port) then Src := GN.Backend_Node (GN.Identifier (Gaia_Port)); if not GNU.Is_Empty (GN.Destinations (Gaia_Port)) then Dest_Gaia := GN.First_Node (GN.Destinations (Gaia_Port)); if Dest_Gaia /= No_Node then -- The case where their is only one destination -- has to be managed as a specific case, -- so we can simplify the generated graph if GN.Next_Node (Dest_Gaia) = No_Node then -- We link source's buffer to the destination port Dest := Annotation (GN.Frontend_Node (Dest_Gaia)); Src_Trans := Push_Transition (GN.Backend_Node (GN.Identifier (Dest))); Connect := Make_Connection_Statement (Port_Reference (Src), Src_Trans, True); Add_Domain_To_Node (Refered_Node (GPN.First_Node (Domains (Port_Reference (Src)))), Connect); Add_Token_Value_To_Arc (Connect, Thread_Color (Src), Control_Color); GPNU.Append_Node_To_List (Connect, GPN.Connections (Root_Node)); -- we make from destination's Ack node to -- current thread's acknowledgmenet receiver Connect := Make_Connection_Statement (Ack_Place (GN.Backend_Node (GN.Identifier (Dest))), Ack_Receiver_Transition (Thread_Reference (Src)), True); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Root_Node)); else -- We create a transition which will factorize -- multiples connexions Set_Str_To_Name_Buffer ("diff"); Name := Name_Find; P := Translate_Position (Position (Port_Reference (Src))); Diff := GPNU.Make_Transition_Declaration (Name, P); GPN.Set_Scoped_Name (Diff, GPNU.Make_Scoped_Name (Diff, Port_Reference (Src), Name)); GPNU.Append_Node_To_List (Diff, GPN.Transitions (Root_Node)); Connect := Make_Connection_Statement (Port_Reference (Src), Diff, True); Add_Domain_To_Node (Refered_Node (GPN.First_Node (Domains (Port_Reference (Src)))), Connect); Add_Token_Value_To_Arc (Connect, Thread_Color (Src), Control_Color); GPNU.Append_Node_To_List (Connect, GPN.Connections (Root_Node)); while Dest_Gaia /= No_Node loop -- We create a new place for each destination -- (because of PN' semantics) Dest := Annotation (GN.Frontend_Node (Dest_Gaia)); Src_Trans := Push_Transition (GN.Backend_Node (GN.Identifier (Dest))); Set_Str_To_Name_Buffer ("pl"); Name := Name_Find; P := Translate_Position (Position (Src_Trans)); Pl := GPNU.Make_Place_Declaration (Name, P); GPN.Set_Scoped_Name (Pl, GPNU.Make_Scoped_Name (Pl, Src_Trans, Name)); GPNU.Append_Node_To_List (Pl, GPN.Places (Root_Node)); Add_Domain_To_Node (Refered_Node (GPN.First_Node (Domains (Port_Reference (Src)))), Pl); Connect := Make_Connection_Statement (Diff, Pl, False); Add_Domain_To_Node (Refered_Node (GPN.First_Node (Domains (Port_Reference (Src)))), Connect); Add_Token_Value_To_Arc (Connect, Thread_Color (Src), Control_Color); GPNU.Append_Node_To_List (Connect, GPN.Connections (Root_Node)); -- We link source's buffer to the destination port Connect := Make_Connection_Statement (Pl, Src_Trans, True); Add_Domain_To_Node (Refered_Node (GPN.First_Node (Domains (Port_Reference (Src)))), Connect); Add_Token_Value_To_Arc (Connect, Thread_Color (Src), Control_Color); GPNU.Append_Node_To_List (Connect, GPN.Connections (Root_Node)); -- we make from destination's Ack node to -- current thread's acknowledgmenet receiver Connect := Make_Connection_Statement (Ack_Place (GN.Backend_Node (GN.Identifier (Dest))), Ack_Receiver_Transition (Thread_Reference (Src)), True); Add_Domain_To_Node (Control_Color, Connect); GPNU.Append_Node_To_List (Connect, GPN.Connections (Root_Node)); -- For each iteration below the first one, we need -- to incrment the number of replies expected by the -- sender thread. if not First_Iter then Pl := Ack_Receiver_Link (Thread_Reference (Src)); Pl := Refered_Node (GPN.First_Node (Domains (Pl))); Val := Integer (OAV.Value (Number (Pl)).IVal) + 1; Set_Number (Pl, New_Integer_Value (unsigned_long_long (Val))); end if; Dest_Gaia := GN.Next_Node (Dest_Gaia); First_Iter := False; end loop; end if; end if; end if; end if; end Connect_To_Others_Threads; -------------------- -- Process_Thread -- -------------------- procedure Process_Thread (Gaia_Thread, Parent : Types.node_id; L : in out node_location) is use OAV; pragma assert (Gaia_Thread /= No_Node and then GN.Kind (Gaia_Thread) = GN.k_thread); List_Node : node_id; Thread : node_id; Connection : node_id; Connect_1 : node_id; Connect_2 : node_id; Starter : node_id; Stoper : node_id; Start_Trans : node_id; Stop_Trans : node_id; Name : name_id; Choose, Join : node_id; F, G, H : node_id; P : node_location; P2 : node_location; Extrema : node_location; Cnx_Base : node_location; Color : node_id; Color_Dest : node_id; Th_Color : value_id; Seq_Calls : Integer := 0; Out_Ports : Integer := 0; begin Thread := GPNU.Make_Thread_Box; GPN.Set_Identifier (Thread, GPNU.Make_Identifier (Thread, GN.Name (GN.Identifier (Gaia_Thread)))); GPN.Set_Scoped_Name (Thread, GPNU.Make_Scoped_Name (Thread, Parent, GN.Name (GN.Identifier (GN.Scoped_Name (Gaia_Thread))))); Set_Backend_Node (GN.Identifier (Gaia_Thread), Thread); -- We add a special value to the control node for the -- thread Set_Str_To_Name_Buffer ("th_" & Image (Thread)); Th_Color := New_String_Value (Name_Find); F := GPNU.Make_Symbolic_Value (Th_Color); Append_Node_To_List (F, GPN.Symbolic_Values (Control_Color)); GPN.Set_Color_Value (Thread, Th_Color); P := L; Extrema := L; -- We process thread ports' if GN.Ports (Gaia_Thread) /= No_List then List_Node := GN.First_Node (GN.Ports (Gaia_Thread)); while Present (List_Node) loop Process_Port (List_Node, Thread, Out_Ports); List_Node := GN.Next_Node (List_Node); end loop; end if; -- Create the thread.reset transition so that subprogram calls -- could refere it. Set_Str_To_Name_Buffer ("reset"); Name := Name_Find; Stop_Trans := GPNU.Make_Transition_Declaration (Name); GPN.Set_Scoped_Name (Stop_Trans, GPNU.Make_Scoped_Name (Stop_Trans, Thread, Name)); GPNU.Append_Node_To_List (Stop_Trans, GPN.Transitions (Thread)); if Full_Naming_Policy then Set_Reset_Transition (Thread, Stop_Trans); else Current_Thread := Stop_Trans; end if; -- We process call sequences if GN.Call_Sequences (Gaia_Thread) /= No_List then -- Create a launcher place with 1 token Set_Str_To_Name_Buffer ("starter"); Name := Name_Find; Starter := GPNU.Make_Place_Declaration (Name, P); Inc_X (P); Add_Token_To_Place (Starter, Valid_Color_Obj, Control_Color); Add_Domain_To_Node (Control_Color, Starter); GPN.Set_Scoped_Name (Starter, GPNU.Make_Scoped_Name (Starter, Thread, Name)); GPNU.Append_Node_To_List (Starter, GPN.Places (Thread)); -- Create the thread.start transition Set_Str_To_Name_Buffer ("start"); Name := Name_Find; Start_Trans := GPNU.Make_Transition_Declaration (Name, P); Inc_X (P); GPN.Set_Scoped_Name (Start_Trans, GPNU.Make_Scoped_Name (Start_Trans, Thread, Name)); GPNU.Append_Node_To_List (Start_Trans, GPN.Transitions (Thread)); -- Create the thread.choose place Set_Str_To_Name_Buffer ("choose"); Name := Name_Find; Choose := GPNU.Make_Place_Declaration (Name, P); Inc_X (P); Add_Domain_To_Node (Control_Color, Choose); GPN.Set_Scoped_Name (Choose, GPNU.Make_Scoped_Name (Choose, Thread, Name)); GPNU.Append_Node_To_List (Choose, GPN.Places (Thread)); -- connect sequence calls List_Node := GN.First_Node (GN.Call_Sequences (Gaia_Thread)); P2.X := P.X; P2.Y := P.Y; Extrema.X := P2.X; while Present (List_Node) loop -- Call Sequence counter Seq_Calls := Seq_Calls + 1; Process_Statement (List_Node, Thread, Thread, P2); -- we update extrema Extrema.X := Natural'max (Extrema.X, P2.X); Extrema.Y := Natural'max (Extrema.Y, P2.Y); -- re-align on X axis for parallelism P2.X := P.X; List_Node := GN.Next_Node (List_Node); end loop; if Seq_Calls = 0 then Inc_X (Extrema); end if; P.X := Extrema.X; -- Create the thread.join place Set_Str_To_Name_Buffer ("join"); Name := Name_Find; Join := GPNU.Make_Place_Declaration (Name, P); Inc_X (P); Add_Domain_To_Node (Control_Color, Join); GPN.Set_Scoped_Name (Join, GPNU.Make_Scoped_Name (Join, Thread, Name)); GPNU.Append_Node_To_List (Join, GPN.Places (Thread)); -- Set position for the thread.reset transition -- and place it under Y axis extremum Make_Position (Stop_Trans, P); Inc_X (P); -- Set the thread.Ack_Receiver place & transition and link them -- to the reset transition if Out_Ports > 0 then Set_Str_To_Name_Buffer ("recved"); Name := Name_Find; Inc_X (P); H := GPNU.Make_Place_Declaration (Name, P); Add_Domain_To_Node (Control_Color, H); GPN.Set_Scoped_Name (H, GPNU.Make_Scoped_Name (H, Thread, Name)); Set_Str_To_Name_Buffer ("ack_recv"); Name := Name_Find; Inc_X (P); G := GPNU.Make_Transition_Declaration (Name, P); GPN.Set_Scoped_Name (G, GPNU.Make_Scoped_Name (G, Thread, Name)); Make_Equal_Guard (G, Control_Color, Color_Variable (Control_Color), Th_Color); Set_Ack_Receiver_Transition (Thread, G); Connect_1 := Make_Connection_Statement (G, H, False); Add_Domain_To_Node (Control_Color, Connect_1); GPNU.Append_Node_To_List (G, GPN.Transitions (Thread)); GPNU.Append_Node_To_List (H, GPN.Places (Thread)); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); Connect_1 := Make_Connection_Statement (H, Stop_Trans, True); Add_Domain_To_Node (Control_Color, Connect_1, New_Integer_Value (unsigned_long_long (Out_Ports))); Set_Ack_Receiver_Link (Thread, Connect_1); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); end if; -- Create a stoper place Set_Str_To_Name_Buffer ("stoper"); Name := Name_Find; Stoper := GPNU.Make_Place_Declaration (Name, P); Inc_X (P); Add_Domain_To_Node (Control_Color, Stoper); GPN.Set_Scoped_Name (Stoper, GPNU.Make_Scoped_Name (Stoper, Thread, Name)); GPNU.Append_Node_To_List (Stoper, GPN.Places (Thread)); -- Link them all Connect_1 := Make_Connection_Statement (Starter, Start_Trans, True); Add_Domain_To_Node (Control_Color, Connect_1); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); Connect_2 := Make_Connection_Statement (Stop_Trans, Stoper, False); Add_Domain_To_Node (Control_Color, Connect_2); GPNU.Append_Node_To_List (Connect_2, GPN.Connections (Thread)); Connect_1 := Make_Connection_Statement (Start_Trans, Choose, False); Add_Domain_To_Node (Control_Color, Connect_1); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); Connect_2 := Make_Connection_Statement (Join, Stop_Trans, True); Add_Domain_To_Node (Control_Color, Connect_2); GPNU.Append_Node_To_List (Connect_2, GPN.Connections (Thread)); -- Then we have a periodic thread -- We place it over the Y axis extremum -- FIXME : in gaia-processor : make background threads available Set_Str_To_Name_Buffer ("restart"); Name := Name_Find; F := GPNU.Make_Scoped_Name (Starter, Thread, Name); if Out_Ports > 0 then Decr_X (P); Decr_X (P); end if; Decr_X (P); Make_Position (Stop_Trans, P); Inc_Y (Extrema); P.Y := Extrema.Y; Decr_X (P); Make_Position (Starter, P); Make_Position (Stoper, P); P.Y := L.Y; Inc_X (P); Inc_X (P); Inc_X (P); Inc_X (P); F := Make_Place_Fusion (Starter, Stoper, F); GPNU.Append_Node_To_List (F, GPN.Places_Fusions (Thread)); -- Connect call sequences List_Node := GPN.First_Node (GPN.Sub_Components (Thread)); while Present (List_Node) loop Connect_1 := Make_Connection_Statement (Choose, Begin_Node (List_Node), True); Add_Domain_To_Node (Control_Color, Connect_1); Connect_2 := Make_Connection_Statement (End_Node (List_Node), Join, False); Add_Domain_To_Node (Control_Color, Connect_2); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); GPNU.Append_Node_To_List (Connect_2, GPN.Connections (Thread)); List_Node := GPN.Next_Node (List_Node); end loop; end if; -- We create the places for threads ports Inc_Y (Extrema); Cnx_Base.Y := Extrema.Y; Cnx_Base.X := L.X; Inc_Y (Extrema); Inc_X (Cnx_Base); if GPN.Fifos (Thread) /= No_List then List_Node := GPN.First_Node (GPN.Fifos (Thread)); while List_Node /= No_Node loop Make_Fifos_Location (List_Node, Cnx_Base); Inc_X (Cnx_Base); List_Node := GPN.Next_Node (List_Node); end loop; end if; Extrema.X := Natural'max (Extrema.X, Cnx_Base.X); Inc_Y (Extrema); Cnx_Base.Y := Extrema.Y; Cnx_Base.X := L.X; Inc_X (Cnx_Base); -- We make links for thread's connections if not GNU.Is_Empty (GN.Connections (Gaia_Thread)) then List_Node := GN.First_Node (GN.Connections (Gaia_Thread)); while Present (List_Node) loop -- Create the connection (transition) Name := GN.Name (GN.Identifier (GN.Scoped_Name (List_Node))); Connection := GPNU.Make_Transition_Declaration (Name, Cnx_Base); Inc_X (Cnx_Base); GPN.Set_Scoped_Name (Connection, GPNU.Make_Scoped_Name (Connection, Thread, Name)); GPNU.Append_Node_To_List (Connection, GPN.Transitions (Thread)); Color := Refered_Node (GPN.First_Node (Domains (Port_Reference (GN.Backend_Node (GN.Identifier (GN.Source (List_Node))))))); Color_Dest := Refered_Node (GPN.First_Node (Domains (Port_Reference (GN.Backend_Node (GN.Identifier (GN.Destination (List_Node))))))); -- Create a link from source to Connect (connection) Connect_1 := Make_Connection_Statement (Port_Reference (GN.Backend_Node (GN.Identifier (GN.Source (List_Node)))), Connection, True); Add_Domain_To_Node (Color, Connect_1); -- If source is a port if GN.Source_Subprogram_Call (List_Node) = No_Node then -- We add control color to domain Add_Domain_To_Node (Control_Color, Connect_1); -- We link the connexion to the related ack place Connect_2 := Make_Connection_Statement (Connection, Ack_Place (GN.Backend_Node (GN.Identifier (GN.Source (List_Node)))), False); Add_Domain_To_Node (Control_Color, Connect_2); GPNU.Append_Node_To_List (Connect_2, GPN.Connections (Thread)); end if; GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); -- Create a link from Connect (connection) to destination Connect_2 := Make_Connection_Statement (Connection, Port_Reference (GN.Backend_Node (GN.Identifier (GN.Destination ((List_Node))))), False); Add_Domain_To_Node (Color_Dest, Connect_2); GPNU.Append_Node_To_List (Connect_2, GPN.Connections (Thread)); -- If Source is a parameter -- Link back Connect (connection) to source if GN.Source_Subprogram_Call (List_Node) /= No_Node then Connect_1 := Make_Connection_Statement (Connection, Port_Reference (GN.Backend_Node (GN.Identifier (GN.Source ((List_Node))))), False); Add_Domain_To_Node (Color, Connect_1); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); -- Put a guard on Connection transition -- so that the connection couldn't read paramater initial -- default value. Make_Guard (Connection, Color, Color_Variable (Color), Invalid_Color_Obj); end if; List_Node := GN.Next_Node (List_Node); end loop; end if; if Seq_Calls = 0 then -- We set a default transition which represent empty body Set_Str_To_Name_Buffer ("body"); Name := Name_Find; F := GPNU.Make_Transition_Declaration (Name, P2); GPN.Set_Scoped_Name (F, GPNU.Make_Scoped_Name (F, Thread, Name)); GPNU.Append_Node_To_List (F, GPN.Transitions (Thread)); -- We establish connections Connect_1 := Make_Connection_Statement (Choose, F, True); Add_Domain_To_Node (Control_Color, Connect_1); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); Connect_1 := Make_Connection_Statement (F, Join, False); Add_Domain_To_Node (Control_Color, Connect_1); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); -- We connect the so-called "empty" body with ports -- (I guess we have no choices here...) if GN.Ports (Gaia_Thread) /= No_List then List_Node := GN.First_Node (GN.Ports (Gaia_Thread)); while Present (List_Node) loop G := GN.Backend_Node (GN.Identifier (List_Node)); if GN.Is_In (List_Node) then Connect_1 := Make_Connection_Statement (Port_Reference (G), F, True); Add_Domain_To_Node (Control_Color, Connect_1); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); -- We link the transition with Ack_Place Connect_1 := Make_Connection_Statement (F, Ack_Place (G), False); Add_Domain_To_Node (Control_Color, Connect_1); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); else Connect_1 := Make_Connection_Statement (F, Port_Reference (G), False); Add_Domain_To_Node (Control_Color, Connect_1); GPNU.Append_Node_To_List (Connect_1, GPN.Connections (Thread)); end if; List_Node := GN.Next_Node (List_Node); end loop; end if; else if Seq_Calls >= 2 then -- We have non-deterministic sequences calls -- so we set a call to an optional behavioural definition Set_Include_Call (Thread, Make_Include_Call ("UD", Gaia_Thread)); end if; end if; Extrema.X := Natural'max (Extrema.X, Cnx_Base.X); L.X := Natural'max (Extrema.X, P.X); L.Y := Extrema.Y; GPNU.Append_Node_To_List (Thread, GPN.Sub_Components (Parent)); end Process_Thread; --------------------- -- Connect_Threads -- --------------------- procedure Connect_Threads (Gaia_Thread, Root_Node : node_id) is pragma assert (Gaia_Thread /= No_Node and then GN.Kind (Gaia_Thread) = GN.k_thread); List_Node : node_id; begin if GN.Ports (Gaia_Thread) /= No_List then List_Node := GN.First_Node (GN.Ports (Gaia_Thread)); while Present (List_Node) loop Connect_To_Others_Threads (List_Node, Root_Node); List_Node := GN.Next_Node (List_Node); end loop; end if; end Connect_Threads; --------------------- -- Process_Process -- --------------------- procedure Process_Process (Gaia_Process, Parent : Types.node_id; L : in out node_location) is pragma assert (Gaia_Process /= No_Node and then GN.Kind (Gaia_Process) = GN.k_process); Process : node_id; Name : name_id; List_Node : node_id; P : node_location := L; begin Process := GPNU.Make_Container; Name := GN.Name (GN.Identifier (Gaia_Process)); GPN.Set_Identifier (Process, GPNU.Make_Identifier (Process, Name)); GPN.Set_Scoped_Name (Process, GPNU.Make_Scoped_Name (Process, Parent, Name)); -- We process threads if GN.Threads (Gaia_Process) /= No_List then List_Node := GN.First_Node (GN.Threads (Gaia_Process)); while Present (List_Node) loop Process_Thread (GN.Corresponding_Thread (List_Node), Process, P); -- re-align on Y axis for parallelism P.X := L.X; Inc_Y (P); List_Node := GN.Next_Node (List_Node); end loop; end if; L := P; GPNU.Append_Node_To_List (Process, GPN.Sub_Components (Parent)); end Process_Process; --------------------- -- Connect_Process -- --------------------- procedure Connect_Process (Gaia_Process, Root_Node : node_id) is pragma assert (Gaia_Process /= No_Node and then GN.Kind (Gaia_Process) = GN.k_process); List_Node : node_id; begin -- we link threads togethers via connexions if GN.Threads (Gaia_Process) /= No_List then List_Node := GN.First_Node (GN.Threads (Gaia_Process)); while Present (List_Node) loop Connect_Threads (GN.Corresponding_Thread (List_Node), Root_Node); List_Node := GN.Next_Node (List_Node); end loop; end if; end Connect_Process; ---------------------------- -- Process_Namespace_Data -- ---------------------------- procedure Process_Namespace_Data (Gaia_Data_Def, Root, Namespace : node_id) is pragma assert (Root /= No_Node and then GPN.Kind (Root) = GPN.k_root_node); pragma assert (Gaia_Data_Def /= No_Node and then GN.Kind (Gaia_Data_Def) = GN.k_type_definition); Color : node_id; Found : Boolean := False; N : node_id; V : node_id; begin -- First we search weither the color has alrealdy been declared or not if not GPNU.Is_Empty (GPN.Color_Declarations (Root)) then N := GPN.First_Node (GPN.Color_Declarations (Root)); while N /= No_Node loop if Frontend_Node (Gaia_Node (GPN.Identifier (N))) = Frontend_Node (Gaia_Data_Def) then Found := True; exit; end if; N := GPN.Next_Node (N); end loop; end if; if Found then Set_Backend_Node (GN.Identifier (Gaia_Data_Def), N); else -- We build a color according to the data type Color := Make_Color_Declaration (Gaia_Data_Def, Namespace); -- We add special values if not GNU.Is_Empty (GN.Symbolic_Values (Gaia_Data_Def)) then N := GN.First_Node (GN.Symbolic_Values (Gaia_Data_Def)); while N /= No_Node loop V := GPNU.Make_Symbolic_Value (GN.Value_Name (N)); Append_Node_To_List (V, GPN.Symbolic_Values (Color)); N := GN.Next_Node (N); end loop; end if; Set_Backend_Node (GN.Identifier (Gaia_Data_Def), Color); GPNU.Append_Node_To_List (Color, GPN.Color_Declarations (Root)); end if; end Process_Namespace_Data; ------------------------- -- Process_Declaration -- ------------------------- procedure Process_Declaration (Decl, Parent, Root : Types.node_id; L : in out node_location) is P : node_location := L; begin case GN.Kind (Decl) is when GN.k_subprogram => null; when GN.k_thread => null; when GN.k_process => Process_Process (Decl, Parent, P); -- re-align on Y axis for parallelism P.X := L.X; Inc_Y (P); when GN.k_type_definition => Process_Namespace_Data (Decl, Root, Parent); when others => raise Program_Error; end case; L := P; end Process_Declaration; ----------------------- -- Process_Namespace -- ----------------------- procedure Process_Namespace (Gaia_Namespace, Parent, Root : Types.node_id; L : in out node_location) is pragma assert (Gaia_Namespace /= No_Node and then GN.Kind (Gaia_Namespace) = GN.k_namespace); pragma assert (Root /= No_Node and then GPN.Kind (Root) = GPN.k_root_node); List_Node : node_id; Namespace : node_id; P : node_location := L; begin Namespace := GPNU.Make_Container; GPN.Set_Identifier (Namespace, GPNU.Make_Identifier (Namespace, GN.Name (GN.Identifier (Gaia_Namespace)))); GPN.Set_Scoped_Name (Namespace, GPNU.Make_Scoped_Name (Namespace, Parent, GN.Name (GN.Identifier (Gaia_Namespace)))); if GN.Public_Declarations (Gaia_Namespace) /= No_List then List_Node := GN.First_Node (GN.Public_Declarations (Gaia_Namespace)); while Present (List_Node) loop Process_Declaration (List_Node, Namespace, Root, P); List_Node := GN.Next_Node (List_Node); end loop; end if; if GN.Private_Declarations (Gaia_Namespace) /= No_List then List_Node := GN.First_Node (GN.Private_Declarations (Gaia_Namespace)); while Present (List_Node) loop Process_Declaration (List_Node, Namespace, Root, P); List_Node := GN.Next_Node (List_Node); end loop; end if; GPNU.Append_Node_To_List (Namespace, GPN.Sub_Components (Parent)); L := P; end Process_Namespace; ------------------------ -- Connect_Namespaces -- ------------------------ procedure Connect_Namespaces (Gaia_Namespace, Root_Node : Types.node_id) is pragma assert (Gaia_Namespace /= No_Node and then GN.Kind (Gaia_Namespace) = GN.k_namespace); List_Node : node_id; begin if GN.Public_Declarations (Gaia_Namespace) /= No_List then List_Node := GN.First_Node (GN.Public_Declarations (Gaia_Namespace)); while Present (List_Node) loop if GN.Kind (List_Node) = GN.k_process then Connect_Process (List_Node, Root_Node); end if; List_Node := GN.Next_Node (List_Node); end loop; end if; if GN.Private_Declarations (Gaia_Namespace) /= No_List then List_Node := GN.First_Node (GN.Private_Declarations (Gaia_Namespace)); while Present (List_Node) loop if GN.Kind (List_Node) = GN.k_process then Connect_Process (List_Node, Root_Node); end if; List_Node := GN.Next_Node (List_Node); end loop; end if; end Connect_Namespaces; ------------------------ -- Connect_Root_Nodes -- ------------------------ procedure Connect_Root_Nodes (Gaia_Root, Root_Node : node_id) is pragma assert (Gaia_Root /= No_Node and then GN.Kind (Gaia_Root) = GN.k_root_node); List_Node : node_id; begin if GN.Namespaces (Gaia_Root) /= No_List then List_Node := GN.First_Node (GN.Namespaces (Gaia_Root)); while List_Node /= No_Node loop Connect_Namespaces (List_Node, Root_Node); List_Node := GN.Next_Node (List_Node); end loop; end if; end Connect_Root_Nodes; ----------------------- -- Process_Root_Node -- ----------------------- procedure Process_Root_Node (Gaia_Root, Parent : Types.node_id; L : in out node_location) is use Gaia.Utils; pragma assert (Gaia_Root /= No_Node and then GN.Kind (Gaia_Root) = GN.k_root_node); List_Node : node_id; Application_Root : node_id; P : node_location := L; begin Application_Root := GPNU.Make_Container; GPN.Set_Identifier (Application_Root, GPNU.Make_Identifier (Application_Root, GN.Name (GN.Identifier (Gaia_Root)))); GPN.Set_Scoped_Name (Application_Root, GPNU.Make_Scoped_Name (Application_Root, No_Node, GN.Name (GN.Identifier (Gaia_Root)))); if GN.Namespaces (Gaia_Root) /= No_List then -- We build the whole system, less high-level connections -- (connection between system's and process' ports) List_Node := GN.First_Node (GN.Namespaces (Gaia_Root)); while List_Node /= No_Node loop Process_Namespace (List_Node, Application_Root, Parent, P); -- re-align on Y axis for parallelism P.X := L.X; List_Node := GN.Next_Node (List_Node); end loop; else -- Create a void process (just a transition) -- Transition's name is "$(process_name)_$(process_name)" GPNU.Append_Node_To_List (GPNU.Make_Transition_Declaration (GPN.Name (GPN.Identifier (Application_Root)), Application_Root), GPN.Transitions (Application_Root)); end if; L := P; GPNU.Append_Node_To_List (Application_Root, GPN.Sub_Components (Parent)); end Process_Root_Node; ------------------------------------- -- Process_Distributed_Application -- ------------------------------------- function Process_Distributed_Application (DA : Types.node_id; Options : Gaia.Mgmt.gaia_options) return Types.node_id is use Gaia.Mgmt; use Gaia.Utils; Application_Directory : name_id; Application_Node : node_id; Root_Node : node_id; L : constant node_location := (30, 15); P : node_location := L; Normalized_Dir_Name : constant name_id := Processor.Normalize_Name (GN.Name (GN.Identifier (DA))); begin -- Find root name Get_Name_String (Add_Directory_Separator (Options.Output_Directory)); Get_Name_String_And_Append (Normalized_Dir_Name); Application_Directory := Name_Find; -- Create a root node Root_Node := GPNU.Make_Root_Node (Application_Directory, No_Name); GPN.Set_Identifier (Root_Node, GPNU.Make_Identifier (Root_Node, No_Name)); GPN.Set_Scoped_Name (Root_Node, Make_Scoped_Name (Root_Node, No_Node, No_Name)); -- Initialize the control color and variable Make_Control_Color; -- Process the application nodes Application_Node := GN.First_Node (GN.Root_Nodes (DA)); while Present (Application_Node) loop Process_Root_Node (Application_Node, Root_Node, P); Inc_Y (P); -- re-align on Y axis for parallelism P.X := L.X; Application_Node := GN.Next_Node (Application_Node); end loop; -- We proceed high-level connexions Application_Node := GN.First_Node (GN.Root_Nodes (DA)); while Present (Application_Node) loop Connect_Root_Nodes (Application_Node, Root_Node); Application_Node := GN.Next_Node (Application_Node); end loop; return Root_Node; end Process_Distributed_Application; end Gaia.Pn;