taste-concurrency_view.adb 39.2 KB
Newer Older
1
--  *************************** kazoo ***********************  --
Maxime Perrotin's avatar
Maxime Perrotin committed
2
--  (c) 2019 European Space Agency - maxime.perrotin@esa.int
3 4
--  LGPL license, see LICENSE file

Maxime Perrotin's avatar
Maxime Perrotin committed
5 6
with Ada.Directories,
     Ada.IO_Exceptions,
Maxime Perrotin's avatar
Maxime Perrotin committed
7
     Ada.Exceptions,
Maxime Perrotin's avatar
Maxime Perrotin committed
8 9
     Ada.Characters.Latin_1,
     Ada.Strings.Fixed;
Maxime Perrotin's avatar
Maxime Perrotin committed
10 11 12

use Ada.Directories;

13 14
package body TASTE.Concurrency_View is

Maxime Perrotin's avatar
Maxime Perrotin committed
15 16
   Newline : Character renames Ada.Characters.Latin_1.LF;

17
   procedure Debug_Dump (CV : Taste_Concurrency_View; Output : File_Type) is
Maxime Perrotin's avatar
Maxime Perrotin committed
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
      procedure Dump_Partition (Partition : CV_Partition) is
      begin
         for Block of Partition.Blocks loop
            Put_Line (Output, "Protected Block : " & To_String (Block.Name));
            for Provided of Block.Provided loop
               Put_Line (Output, " |_ PI : " & To_String (Provided.Name));
            end loop;
            for Required of Block.Required loop
               Put_Line (Output, " |_ RI : " & To_String (Required.Name));
            end loop;
            for Thread of Block.Calling_Threads loop
               Put_Line (Output, " |_ Calling_Thread : " & Thread);
            end loop;
            if Block.Node.Has_Value then
               Put_Line (Output, " |_ Node : "
                         & To_String (Block.Node.Unsafe_Just.Name));
               declare
                  P : constant Taste_Partition :=
                    Block.Node.Unsafe_Just.Find_Partition
                      (To_String (Block.Name)).Unsafe_Just;
               begin
                  Put_Line (Output, " |_ Partition : " & To_String (P.Name));
                  Put_Line (Output, "   |_ Coverage       : "
                            & P.Coverage'Img);
                  Put_Line (Output, "   |_ Package        : "
                            & To_String (P.Package_Name));
                  Put_Line (Output, "   |_ CPU Name       : "
                            & To_String (P.CPU_Name));
                  Put_Line (Output, "   |_ CPU Platform   : "
                            & P.CPU_Platform'Img);
                  Put_Line (Output, "   |_ CPU Classifier : "
                            & To_String (P.CPU_Classifier));
               end;
            end if;
Maxime Perrotin's avatar
Maxime Perrotin committed
52
         end loop;
53

Maxime Perrotin's avatar
Maxime Perrotin committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
         for Thread of Partition.Threads loop
            Put_Line (Output, "Thread : " & To_String (Thread.Name));
            Put_Line (Output, " |_ Port : "
                      & To_String (Thread.Entry_Port_Name));
            Put_Line (Output, " |_ Protected Block : "
                      & To_String (Thread.Protected_Block_Name));
            Put_Line (Output, " |_ Node : "
                      & To_String (Thread.Node.Value_Or
                        (Taste_Node'(Name   => US ("(none)"),
                                     others => <>)).Name));
            for Out_Port of Thread.Output_Ports loop
               Put_Line (Output, " |_ Output port remote thread : "
                         & To_String (Out_Port.Remote_Thread));
               Put_Line (Output, " |_ Output port remote PI : "
                         & To_String (Out_Port.Remote_PI));
            end loop;
         end loop;
      end Dump_Partition;
   begin
      for Node of CV.Nodes loop
         for Partition of Node.Partitions loop
            Dump_Partition (Partition);
Maxime Perrotin's avatar
Maxime Perrotin committed
76
         end loop;
77 78 79
      end loop;
   end Debug_Dump;

80
   --  This function translates a protected block into a template
81
   function Prepare_Template (B : Protected_Block) return Block_As_Template is
82
      Calling_Threads : Tag;
83
      Result          : Block_As_Template;
84 85 86 87 88
   begin
      for Thread of B.Calling_Threads loop
         Calling_Threads := Calling_Threads & Thread;
      end loop;

89 90 91 92
      for PI of B.Provided loop
         declare
            Basic : constant Translate_Set := PI.PI.To_Template
              & Assoc ("Protected_Block_Name", To_String (PI.Name))
93 94
              & Assoc ("Caller_Is_Local", PI.Local_Caller)
              & Assoc ("Calling_Threads", Calling_Threads);
95
         begin
Maxime Perrotin's avatar
Maxime Perrotin committed
96 97 98 99 100
            if PI.PI.RCM = Protected_Operation then
               Result.Protected_Provided.Append (Basic);
            else
               Result.Unprotected_Provided.Append (Basic);
            end if;
101 102 103 104
         end;
      end loop;

      for RI of B.Required loop
105 106
         Result.Required.Append (RI.To_Template
                                 & Assoc ("Calling_Threads", Calling_Threads));
107 108 109
      end loop;

      Result.Header := +Assoc  ("Name",            To_String (B.Name))
110
                       & Assoc ("Language",        B.Language)
111 112 113 114
                       & Assoc ("Calling_Threads", Calling_Threads)
                       & Assoc ("Node_Name",       To_String (B.Node.Value_Or
                         (Taste_Node'(Name => US (""), others => <>)).Name));
      return Result;
115
   end Prepare_Template;
116 117

   --  This function translates a thread definition into a template
Maxime Perrotin's avatar
Maxime Perrotin committed
118
   function To_Template (T : AADL_Thread) return Translate_Set is
119
      Remote_Thread    : Vector_Tag;
Maxime Perrotin's avatar
Maxime Perrotin committed
120
      RI_Port_Name     : Vector_Tag;  --  Name of the local RI (= port name)
121 122 123
      Remote_PI        : Vector_Tag;  --  Name of the remote PI
      Remote_PI_Sort   : Vector_Tag;  --  ASN.1 type of the parameter
      Remote_PI_Module : Vector_Tag;  --  ASN.1 module containing the type
124 125
   begin
      for Out_Port of T.Output_Ports loop
Maxime Perrotin's avatar
Maxime Perrotin committed
126
         RI_Port_Name  := RI_Port_Name & Out_Port.Name;
127 128
         Remote_Thread := Remote_Thread & To_String (Out_Port.Remote_Thread);
         Remote_PI     := Remote_PI     & To_String (Out_Port.Remote_PI);
129 130 131 132 133 134 135 136 137 138
         --  Set the Asn.1 module and type of the optional RI parameter
         if Out_Port.RI.Params.Length > 0 then
            Remote_PI_Sort := Remote_PI_Sort
              & Out_Port.RI.Params.First_Element.Sort;
            Remote_PI_Module := Remote_PI_Module
              & Out_Port.RI.Params.First_Element.ASN1_Module;
         else
            Remote_PI_Sort   := Remote_PI_Sort   & "";
            Remote_PI_Module := Remote_PI_Module & "";
         end if;
139 140 141
      end loop;

      return Result : constant Translate_Set :=
142 143
        T.PI.To_Template   --  Template of the PI used to create the thread
        & Assoc ("Thread_Name",       To_String (T.Name))
144
        & Assoc ("Partition_Name",    To_String (T.Partition_Name))
145 146
        & Assoc ("Entry_Port_Name",   To_String (T.Entry_Port_Name))
        & Assoc ("RCM",               To_String (T.RCM))
Maxime Perrotin's avatar
Maxime Perrotin committed
147
        & Assoc ("Need_Mutex",        T.Need_Mutex)
148 149 150 151
        & Assoc ("Pro_Block_Name",    To_String (T.Protected_Block_Name))
        & Assoc ("Node_Name",         To_String (T.Node.Value_Or
          (Taste_Node'(Name => US (""), others => <>)).Name))
        & Assoc ("Remote_Threads",    Remote_Thread)
Maxime Perrotin's avatar
Maxime Perrotin committed
152
        & Assoc ("RI_Port_Names",     RI_Port_Name)
153 154 155
        & Assoc ("Remote_PIs",        Remote_PI)
        & Assoc ("Remote_PI_Sorts",   Remote_PI_Sort)
        & Assoc ("Remote_PI_Modules", Remote_PI_Module);
Maxime Perrotin's avatar
Maxime Perrotin committed
156
   end To_Template;
157

Maxime Perrotin's avatar
Maxime Perrotin committed
158
   --  Generate the code by iterating over template folders
159
   procedure Generate_Code (CV : Taste_Concurrency_View)
160
   is
Maxime Perrotin's avatar
Maxime Perrotin committed
161
      Prefix   : constant String := CV.Base_Template_Path.Element
Maxime Perrotin's avatar
Maxime Perrotin committed
162 163 164 165 166 167
        & "templates/concurrency_view";
      --  To iterate over template folders
      ST       : Search_Type;
      Current  : Directory_Entry_Type;
      Filter   : constant Filter_Type := (Directory => True,
                                          others    => False);
168 169
      Output_File      : File_Type;

170
      CV_Out_Dir  : constant String  :=
Maxime Perrotin's avatar
Maxime Perrotin committed
171
        CV.Base_Output_Path.Element & "/build/";
172 173 174 175 176 177

      --  Tags that are built over the whole system
      --  and cleant up between each template folder:
      Threads          : Unbounded_String;
      All_Thread_Names : Tag;  --  Complete list of threads
      All_Target_Names : Tag;  --  List of all targets used (AADL packages)
178
      All_Block_Names  : Tag;  --  Complete list of blocks
179
   begin
180
      Put_Debug ("Concurrency View templates expected in " & Prefix);
Maxime Perrotin's avatar
Maxime Perrotin committed
181 182 183 184 185 186 187 188 189 190 191 192 193
      Start_Search (Search    => ST,
                    Pattern   => "",
                    Directory => Prefix,
                    Filter    => Filter);

      if not More_Entries (ST) then
         --  On Unix, this will never happen because "." and ".." are part
         --  of the search result. We'll only get an IO Error if the
         --  concurrency_view folder itself does not exist
         raise Concurrency_View_Error with
           "No folders with templates for concurrency view";
      end if;

194
      --  Iterate over the folders containing template files
Maxime Perrotin's avatar
Maxime Perrotin committed
195
      while More_Entries (ST) loop
196 197 198 199
         --  Clean-up system-wise tags before the next template folder:
         Threads := US ("");
         Clear (All_Thread_Names);
         Clear (All_Target_Names);
200
         Clear (All_Block_Names);
201

Maxime Perrotin's avatar
Maxime Perrotin committed
202 203 204 205 206 207 208
         Get_Next_Entry (ST, Current);

         --  Ignore Unix special directories
         if Simple_Name (Current) = "." or Simple_Name (Current) = ".." then
            goto continue;
         end if;

Maxime Perrotin's avatar
Maxime Perrotin committed
209
         declare
Maxime Perrotin's avatar
Maxime Perrotin committed
210 211
            Path  : constant String  := Full_Name (Current);

212 213
            function Generate_Partition (Node_Name      : String;
                                         Partition_Name : String)
Maxime Perrotin's avatar
Maxime Perrotin committed
214
                                         return String
Maxime Perrotin's avatar
Maxime Perrotin committed
215
            is
Maxime Perrotin's avatar
Maxime Perrotin committed
216 217
               Partition       : constant CV_Partition :=
                 CV.Nodes (Node_Name).Partitions (Partition_Name);
218 219
               Thread_Names,
               Thread_Has_Param : Vector_Tag;
220 221
               Block_Names     : Vector_Tag;
               Block_Languages : Vector_Tag;
Maxime Perrotin's avatar
Maxime Perrotin committed
222
               Blocks          : Unbounded_String;
223
               Part_Threads    : Unbounded_String;
Maxime Perrotin's avatar
Maxime Perrotin committed
224
               Partition_Assoc : Translate_Set;
225
               --  Connections between threads:
226
               Thread_Src_Name,
227
               Thread_Src_Port : Vector_Tag;
228
               Thread_Dst_Name,
229
               Thread_Dst_Port : Vector_Tag;
230 231 232 233
               Input_Port_Names,
               Input_Port_Type_Name,
               Input_Port_Thread_Name  : Vector_Tag;
               Output_Port_Names,
234 235 236
               Output_Port_Type_Name   : Vector_Tag;
               Part_Out_Port_Names,  --  there can be multiple threads
               Connected_Threads : Vector_Tag;  -- on one partition outport
237

238 239 240 241 242 243 244 245 246 247
               --  Optionally generate partition code in separate files
               --  (if filepart.tmplt is present and contains a filename)
               File_Id         : constant String := Path & "/filepart.tmplt";
               Part_Check      : constant Boolean := Exists (File_Id);
               Part_Tag        : constant Translate_Set :=
                 +Assoc ("Partition_Name", Partition_Name);
               Part_File_Name  : constant String :=
                 (if Part_Check then Strip_String (Parse (File_Id, Part_Tag))
                  else "");
               Part_Content    : Unbounded_String;
Maxime Perrotin's avatar
Maxime Perrotin committed
248 249
               --  Part_File_Name may contain a subfolder
               Subfolder       : Unbounded_String;
Maxime Perrotin's avatar
Maxime Perrotin committed
250
            begin
251 252 253 254 255 256 257 258 259 260 261
               for Each of Partition.In_Ports loop
                  Input_Port_Names := Input_Port_Names & Each.Port_Name;
                  Input_Port_Type_Name := Input_Port_Type_Name
                    & Each.Type_Name;
                  Input_Port_Thread_Name :=
                    Input_Port_Thread_Name & Each.Thread_Name;
               end loop;
               for Each of Partition.Out_Ports loop
                  Output_Port_Names := Output_Port_Names & Each.Port_Name;
                  Output_Port_Type_Name := Output_Port_Type_Name
                    & Each.Type_Name;
262 263 264 265 266 267
                  --  Set the connection between threads and partition outports
                  for T of Each.Connected_Threads loop
                     Part_Out_Port_Names := Part_Out_Port_Names
                       & Each.Port_Name;
                     Connected_Threads := Connected_Threads & T;
                  end loop;
268 269
               end loop;

270 271 272
               for T of Partition.Threads loop
                  declare
                     --  Render each thread
273
                     Name         : constant String := To_String (T.Name);
274 275
                     Thread_Assoc : constant Translate_Set :=
                       Join_Sets (T.To_Template, CV.Configuration.To_Template);
276
                     Result       : constant String :=
277
                       (Parse (Path & "/thread.tmplt", Thread_Assoc));
278 279 280 281 282 283 284 285 286 287 288 289 290

                     --  Optionally generate thread code in separate files
                     --  (if filethread.tmplt present and contains a filename)
                     Thread_File_Id   : constant String :=
                       Path & "/filethread.tmplt";
                     Thread_Check     : constant Boolean :=
                       Exists (Thread_File_Id);
                     Thread_Tag       : constant Translate_Set :=
                       +Assoc ("Thread_Name", Name);
                     Thread_File_Name : constant String :=
                       (if Thread_Check
                        then Strip_String (Parse (Thread_File_Id, Thread_Tag))
                        else "");
291
                  begin
292
                     Threads      := Threads & Newline & Result;
293
                     Part_Threads := Part_Threads & Newline & Result;
294
                     Thread_Names := Thread_Names & Name;
295 296 297 298 299 300
                     --  Set boolean to true if thread has a param
                     --  That helps backend to know if POHI has generated
                     --  the "types" package.
                     Thread_Has_Param := Thread_Has_Param &
                       (T.PI.Params.Length > 0);

301
                     All_Thread_Names := All_Thread_Names & Name;
302
                     for P of T.Output_Ports loop
303 304 305 306 307 308 309 310 311 312 313 314 315
                        for Part_Threads of Partition.Threads loop
                           --  Create partition ports only when source and
                           --  destination are in the same partition
                           if P.Remote_Thread = Part_Threads.Name then
                              Thread_Src_Name := Thread_Src_Name & Name;
                              Thread_Src_Port := Thread_Src_Port
                                & To_String (P.Name);
                              Thread_Dst_Name := Thread_Dst_Name
                                & To_String (P.Remote_Thread);
                              Thread_Dst_Port := Thread_Dst_Port
                                & To_String (P.Remote_PI);
                           end if;
                        end loop;
316
                     end loop;
317 318 319 320 321 322 323 324 325 326 327 328
                     --  Save the content of the thread in a file
                     --  (if required at template folder level)
                     if Thread_File_Name /= "" then
                        Create_Path (CV_Out_Dir & Node_Name);
                        Create (File => Output_File,
                                Mode => Out_File,
                                Name =>
                                  CV_Out_Dir & Node_Name
                                & "/" & Thread_File_Name);
                        Put_Line (Output_File, Result);
                        Close (Output_File);
                     end if;
329
                  end;
Maxime Perrotin's avatar
Maxime Perrotin committed
330
               end loop;
331

332 333
               for B of Partition.Blocks loop
                  declare
Maxime Perrotin's avatar
Maxime Perrotin committed
334 335
                     Block_Name   : constant String := To_String (B.Name);
                     Tmpl         : constant Block_As_Template :=
336
                       B.Prepare_Template;
Maxime Perrotin's avatar
Maxime Perrotin committed
337 338 339 340 341
                     Block_Assoc  : Translate_Set := Tmpl.Header;
                     Pro_PI_Tag   : Unbounded_String;
                     Unpro_PI_Tag : Unbounded_String;
                     RI_Tag       : Unbounded_String;
                     Result       : Unbounded_String;
342 343 344 345 346 347 348 349 350 351 352 353 354

                     --  Optionally generate block code in separate files
                     --  (if fileblock.tmplt present and contains a filename)
                     Block_File_Id   : constant String :=
                       Path & "/fileblock.tmplt";
                     Block_Check     : constant Boolean :=
                       Exists (Block_File_Id);
                     Block_Tag       : constant Translate_Set :=
                       +Assoc ("Block_Name", B.Name);
                     Block_File_Name : constant String :=
                       (if Block_Check
                        then Strip_String (Parse (Block_File_Id, Block_Tag))
                        else "");
355
                  begin
356
                     Block_Names     := Block_Names & Block_Name;
357
                     All_Block_Names := All_Block_Names & Block_Name;
358 359
                     Block_Languages := Block_Languages & B.Language;

Maxime Perrotin's avatar
Maxime Perrotin committed
360 361
                     for PI_Assoc of Tmpl.Protected_Provided loop
                        Pro_PI_Tag := Pro_PI_Tag & Newline
362 363 364
                          & String'(Parse (Path & "/pi.tmplt",
                                    PI_Assoc & Assoc
                                      ("Partition_Name", Partition_Name)));
Maxime Perrotin's avatar
Maxime Perrotin committed
365 366 367
                     end loop;
                     for PI_Assoc of Tmpl.Unprotected_Provided loop
                        Unpro_PI_Tag := Unpro_PI_Tag & Newline
368 369 370
                          & String'(Parse (Path & "/pi.tmplt",
                                    PI_Assoc & Assoc
                                      ("Partition_Name", Partition_Name)));
371 372
                     end loop;
                     for RI_Assoc of Tmpl.Required loop
Maxime Perrotin's avatar
Maxime Perrotin committed
373
                        RI_Tag := RI_Tag & Newline
374 375 376
                          & String'(Parse (Path & "/ri.tmplt",
                                    RI_Assoc & Assoc
                                      ("Partition_Name", Partition_Name)));
377
                     end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
378 379 380

                     Block_Assoc :=
                       Join_Sets (Block_Assoc, CV.Configuration.To_Template)
Maxime Perrotin's avatar
Maxime Perrotin committed
381 382 383
                       & Assoc ("Protected_PIs",   Pro_PI_Tag)
                       & Assoc ("Unprotected_PIs", Unpro_PI_Tag)
                       & Assoc ("Required",        RI_Tag);
384

385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
                     Result := Parse (Path & "/block.tmplt", Block_Assoc);

                     Blocks := Blocks & Newline & To_String (Result);

                     --  Save the content of the block in a file
                     --  (if required at template folder level)
                     if Block_File_Name /= "" then
                        Create_Path (CV_Out_Dir & Node_Name);
                        Create (File => Output_File,
                                Mode => Out_File,
                                Name => CV_Out_Dir & Node_Name
                                        & "/" & Block_File_Name);
                        Put_Line (Output_File, To_String (Result));
                        Close (Output_File);
                     end if;
400
                  end;
Maxime Perrotin's avatar
Maxime Perrotin committed
401
               end loop;
402 403 404
               --  Association includes Name, Coverage, CPU Info, etc.
               --  (see taste-deployment_view.ads for the complete list)
               Partition_Assoc := Partition.Deployment_Partition.To_Template
405
                 & Assoc ("Threads",              Part_Threads)
406
                 & Assoc ("Thread_Names",         Thread_Names)
407
                 & Assoc ("Thread_Has_Param",     Thread_Has_Param)
408 409 410 411 412 413 414 415 416
                 & Assoc ("Node_Name",            Node_Name)
                 & Assoc ("Blocks",               Blocks)
                 & Assoc ("Block_Names",          Block_Names)
                 & Assoc ("Block_Languages",      Block_Languages)
                 & Assoc ("In_Port_Names",        Input_Port_Names)
                 & Assoc ("In_Port_Thread_Name",  Input_Port_Thread_Name)
                 & Assoc ("In_Port_Type_Name",    Input_Port_Type_Name)
                 & Assoc ("Out_Port_Names",       Output_Port_Names)
                 & Assoc ("Out_Port_Type_Name",   Output_Port_Type_Name)
417 418
                 & Assoc ("Part_Out_Port_Name",   Part_Out_Port_Names)
                 & Assoc ("Connected_Threads",    Connected_Threads)
419 420 421 422
                 & Assoc ("Thread_Src_Name",      Thread_Src_Name)
                 & Assoc ("Thread_Src_Port",      Thread_Src_Port)
                 & Assoc ("Thread_Dst_Name",      Thread_Dst_Name)
                 & Assoc ("Thread_Dst_Port",      Thread_Dst_Port);
423

424 425 426
               All_Target_Names := All_Target_Names
                 & String'(Get (Get (Partition_Assoc, "Package_Name")));

427 428 429 430 431 432
               Part_Content :=
                 Parse (Path & "/partition.tmplt", Partition_Assoc);

               --  Save the content of the partition in a file
               --  (if required at template folder level)
               if Part_File_Name /= "" then
Maxime Perrotin's avatar
Maxime Perrotin committed
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
                  declare
                     Last_Slash : constant Natural :=
                       Ada.Strings.Fixed.Index
                         (Source    => Part_File_Name,
                          From      => Part_File_Name'Last,
                          Pattern   => "/",
                          Going     => Ada.Strings.Backward);
                  begin
                     Subfolder := US (Part_File_Name (1 .. Last_Slash));
                  exception
                     when Ada.Strings.Index_Error =>
                        Subfolder := US ("");
                  end;

                  Create_Path (CV_Out_Dir & Node_Name
                               & "/" & To_String (Subfolder));
449 450 451 452 453 454 455 456 457
                  Create (File => Output_File,
                          Mode => Out_File,
                          Name =>
                            CV_Out_Dir & Node_Name & "/" & Part_File_Name);
                  Put_Line (Output_File, To_String (Part_Content));
                  Close (Output_File);
               end if;

               return To_String (Part_Content);
Maxime Perrotin's avatar
Maxime Perrotin committed
458
            end Generate_Partition;
Maxime Perrotin's avatar
Maxime Perrotin committed
459

460 461
            --  Generate the code for one node
            function Generate_Node (Node_Name : String) return String is
462 463 464
               Partitions      : Unbounded_String;
               Partition_Names : Tag;
               Node_Assoc      : Translate_Set;
Maxime Perrotin's avatar
Maxime Perrotin committed
465 466 467 468 469
               --  Nodes may contain a list of virtual processors for TSP:
               VP_Names,
               VP_Package_Names,
               VP_Platforms,
               VP_Classifiers  : Vector_Tag;
470
            begin
Maxime Perrotin's avatar
Maxime Perrotin committed
471
               for Partition in CV.Nodes (Node_Name).Partitions.Iterate loop
472 473
                  Partition_Names := Partition_Names
                    & CV_Partitions.Key (Partition);
474 475 476 477
                  Partitions := Partitions & Newline
                    & Generate_Partition
                    (Partition_Name => CV_Partitions.Key (Partition),
                     Node_Name      => Node_Name);
Maxime Perrotin's avatar
Maxime Perrotin committed
478
               end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
479 480 481 482 483 484 485
               for VP of CV.Nodes (Node_Name).Deployment_Node.Virtual_CPUs loop
                  VP_Names         := VP_Names & VP.Name;
                  VP_Package_Names := VP_Package_Names & VP.Package_Name;
                  VP_Platforms     := VP_Platforms & VP.Platform;
                  VP_Classifiers   := VP_Classifiers & VP.Classifier;
               end loop;

Maxime Perrotin's avatar
Maxime Perrotin committed
486
               Node_Assoc := +Assoc ("Partitions", Partitions)
487
                 & Assoc ("Partition_Names", Partition_Names)
Maxime Perrotin's avatar
Maxime Perrotin committed
488 489
                 & Assoc ("Has_Memory", Boolean'
                      (CV.Nodes (Node_Name).Deployment_Node.Memory.Name /= ""))
Maxime Perrotin's avatar
Maxime Perrotin committed
490 491 492 493
                 & Assoc ("VP_Names", VP_Names)
                 & Assoc ("VP_Package_Names", VP_Package_Names)
                 & Assoc ("VP_Platforms", VP_Platforms)
                 & Assoc ("VP_Classifiers", VP_Classifiers)
494 495
                 & Assoc ("Node_Name", Node_Name)
                 & Assoc ("CPU_Name",
Maxime Perrotin's avatar
Maxime Perrotin committed
496
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Name)
497 498 499 500
                 & Assoc ("CPU_Family",
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Family)
                 & Assoc ("CPU_Instance",
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Instance)
501 502 503
                 & Assoc ("CPU_Platform",
                         CV.Nodes (Node_Name).Deployment_Node.CPU_Platform'Img)
                 & Assoc ("CPU_Classifier",
Maxime Perrotin's avatar
Maxime Perrotin committed
504 505 506
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Classifier)
                 & Assoc ("Package_Name",
                          CV.Nodes (Node_Name).Deployment_Node.Package_Name)
507 508
                 & Assoc ("Ada_Runtime",
                         CV.Nodes (Node_Name).Deployment_Node.Ada_Runtime);
509 510
               return Parse (Path & "/node.tmplt", Node_Assoc);
            end Generate_Node;
Maxime Perrotin's avatar
Maxime Perrotin committed
511

512 513 514 515 516
            Nodes           : Unbounded_String;
            Tmpl_File       : constant String  := Path & "/filesys.tmplt";
            Tmpl_Sys        : constant String  := Path & "/system.tmplt";
            Valid_Dir       : constant Boolean := Exists (Tmpl_File);
            File_Sys        : constant String  :=
Maxime Perrotin's avatar
Maxime Perrotin committed
517
              (if Valid_Dir then Strip_String (Parse (Tmpl_File)) else "");
518 519
            Trig_Sys        : constant Boolean := Exists (Tmpl_Sys);
            Set_Sys         : Translate_Set;
Maxime Perrotin's avatar
Maxime Perrotin committed
520 521 522
            Node_Names,                    --  List of nodes
            Node_CPU,                      --  Corresponding CPU name
            Node_CPU_Cls,                  --  Corresponding CPU classifier
Maxime Perrotin's avatar
Maxime Perrotin committed
523 524
            Node_Major_Frame,              --  Corresponding time frame (TSP)
            Node_Has_Memory : Vector_Tag;  --  Corresponding memory flag (TSP)
Maxime Perrotin's avatar
Maxime Perrotin committed
525 526 527
            Partition_Names,               --  List of partitions
            Partition_Node,                --  Corresponding node name
            Partition_CPU,                 --  Corresponding CPU name
Maxime Perrotin's avatar
Maxime Perrotin committed
528
            Partition_Time,                --  Corresponding TSP VP time
Maxime Perrotin's avatar
Maxime Perrotin committed
529
            Partition_VP    : Vector_Tag;  --  for TSP: VP binding
530 531
            Part_Source_Name,
            Part_Source_Port,
532
            Part_Dest_Port,
533
            Part_Dest_Name  : Vector_Tag;  -- Inter-partition connections (TSP)
Maxime Perrotin's avatar
Maxime Perrotin committed
534 535 536
            Bus_Names,
            Bus_AADL_Pkg,
            Bus_Classifier  : Vector_Tag;  --  System busses
537 538
            Device_Names,
            Device_Node_Name,
539
            Device_Partition_Name,
540 541 542 543 544 545 546 547 548
            Device_AADL_Pkg,
            Device_Classifier,
            Device_CPU,
            Device_Configuration,
            Device_Accessed_Bus_Name,
            Device_Accessed_Port_Name,
            Device_ASN1_Filename,
            Device_ASN1_Typename,
            Device_ASN1_Module : Vector_Tag;  --  Device drivers
549 550 551 552 553 554 555

            --  To keep a list of ASN.1 files/modules without duplicates:
            Unique_ASN1_Sorts_Set : String_Sets.Set;
            Unique_ASN1_Files,
            Unique_ASN1_Sorts,
            Unique_ASN1_Modules : Vector_Tag;

556 557 558 559
            Connect_From_Partition,           --  Partition to bus connections
            Connect_Port_Name,
            Connect_Via_Bus    : Vector_Tag;
            Found : Boolean := False;
560
         begin
Maxime Perrotin's avatar
Maxime Perrotin committed
561 562 563 564 565 566 567 568 569 570
            --  Prepare the template tags of system.aadl with the busses
            for Bus of CV.Deployment.Busses loop
               --  The bus user properties are ignored here
               --  Could be added if needed but they would require an
               --  additional template file to process the name/values.
               Bus_Names      := Bus_Names & Bus.Name;
               Bus_AADL_Pkg   := Bus_AADL_Pkg & Bus.AADL_Package;
               Bus_Classifier := Bus_Classifier & Bus.Classifier;
            end loop;

571 572 573 574 575 576 577 578 579 580 581 582 583 584
            --  Bus connections: we need the output port name, partition and
            --  bus name to make the AADL construct. Check Bus_Connection type
            --  in deployment_view.ads if anything else is needed. It does not
            --  directly provide the partition name of the function so we have
            --  to retrieve it here
            for BC : Bus_Connection of CV.Deployment.Connections loop
               Connect_Via_Bus   := Connect_Via_Bus & BC.Bus_Name;
               Connect_Port_Name := Connect_Port_Name & BC.Source_Port;
               Found := False;
               for Node of CV.Deployment.Nodes loop
                  exit when Found;
                  for Part of Node.Partitions loop
                     exit when Found;
                     if Part.Bound_Functions.Contains
585
                       (To_String (BC.Source_Function)) --  Dest_Function))
586 587 588 589 590 591 592 593 594 595
                     then
                        Connect_From_Partition :=
                          Connect_From_Partition & Part.Name;
                        Found := True;
                     end if;
                  end loop;
               end loop;
               if not Found then
                  raise Concurrency_View_Error with
                    "Could not find partition of function "
596
                    & To_String (BC.Source_Function); --  Dest_Function);
597 598 599
               end if;
            end loop;

600 601 602
            for Node in CV.Nodes.Iterate loop
               declare
                  Node_Name    : constant String := CV_Nodes.Key (Node);
Maxime Perrotin's avatar
Maxime Perrotin committed
603
                  Output_Dir   : constant String := CV_Out_Dir & Node_Name;
604 605 606 607 608 609 610 611 612 613 614 615
                  Do_It        : constant Boolean :=
                    Exists (Path & "/filenode.tmplt");
                  Filename_Set : constant Translate_Set :=
                    +Assoc ("Node_Name", Node_Name);
                  --  Get output file name from template
                  File_Name    : constant String :=
                    (if Do_It then
                        Strip_String
                       (Parse (Path & "/filenode.tmplt", Filename_Set))
                     else "");
                  --  Check if file already exists
                  Present      : constant Boolean :=
616 617
                    (File_Name /= ""
                     and then Exists (Output_Dir & "/" & File_Name));
618

619
                  Trig_Tmpl    : constant Translate_Set :=
620 621 622
                    CV.Configuration.To_Template
                    & Assoc ("Filename_Is_Present", Present);

623 624 625 626 627 628 629 630 631 632
                  Trigger      : constant Boolean :=
                    (Node_Name /= "interfaceview"
                     and then Exists (Path & "/trigger.tmplt") and then
                     Strip_String
                       (Parse (Path & "/trigger.tmplt", Trig_Tmpl)) = "TRUE");
                  Node_Content : constant String :=
                    (if Trigger then Generate_Node (Node_Name)
                     else "");
               begin
                  if Trigger then
633 634

                     --  Associate node name, CPU name and CPU classifier
Maxime Perrotin's avatar
Maxime Perrotin committed
635
                     --  Also set flag if a memory region is defined
636
                     --  (this is needed for AADL backends)
Maxime Perrotin's avatar
Maxime Perrotin committed
637
                     Node_Names := Node_Names & Node_Name;
638 639 640 641
                     Node_CPU := Node_CPU
                       & CV.Nodes (Node_Name).Deployment_Node.CPU_Name;
                     Node_CPU_Cls := Node_CPU_Cls
                       & CV.Nodes (Node_Name).Deployment_Node.CPU_Classifier;
Maxime Perrotin's avatar
Maxime Perrotin committed
642 643 644
                     Node_Has_Memory := Node_Has_Memory
                       & (CV.Nodes (Node_Name)
                          .Deployment_Node.Memory.Name /= "");
Maxime Perrotin's avatar
Maxime Perrotin committed
645 646
                     Node_Major_Frame := Node_Major_Frame
                       & CV.Nodes (Node_Name).Deployment_Node.CPU_Duration;
647 648 649 650 651 652 653 654 655 656

                     --  Associate partition name, corresponding node and CPU
                     --  for AADL backends
                     for Partition in CV.Nodes (Node_Name).Partitions.Iterate
                     loop
                        Partition_Names := Partition_Names
                          & CV_Partitions.Key (Partition);
                        Partition_CPU := Partition_CPU
                          & CV_Partitions.Element (Partition)
                          .Deployment_Partition.CPU_Name;
Maxime Perrotin's avatar
Maxime Perrotin committed
657 658 659
                        Partition_VP := Partition_VP
                          & CV_Partitions.Element (Partition)
                          .Deployment_Partition.VP_Name;
660
                        Partition_Node := Partition_Node & Node_Name;
Maxime Perrotin's avatar
Maxime Perrotin committed
661 662 663
                        Partition_Time := Partition_Time
                          & CV_Partitions.Element (Partition)
                          .Deployment_Partition.VP_Duration;
664 665 666 667 668 669 670 671 672 673 674

                        --  Create the inter-partition connections
                        for Out_Port of
                          CV_Partitions.Element (Partition).Out_Ports
                        loop
                           Part_Source_Name := Part_Source_Name
                             & CV_Partitions.Key (Partition);
                           Part_Source_Port := Part_Source_Port
                             & Out_Port.Port_Name;
                           Part_Dest_Name := Part_Dest_Name
                             & Out_Port.Remote_Partition_Name;
675 676
                           Part_Dest_Port := Part_Dest_Port
                             & Out_Port.Remote_Port_Name;
677
                        end loop;
678 679 680
                     end loop;

                     Nodes := Nodes & Newline & Node_Content;
681 682 683 684 685 686 687 688 689 690 691
                     if File_Name /= "" then
                        Create_Path (Output_Dir);
                        Create (File => Output_File,
                                Mode => Out_File,
                                Name => Output_Dir & "/" & File_Name);
                        Put_Line (Output_File, Node_Content);
                        Close (Output_File);
                     end if;
                  end if;
               end;
            end loop;
692 693 694 695 696
            --  Iterate again on the nodes to set the devices
            --  at system level (they could also be added to
            --  nodes if needed, but for the concurrency view
            --  in AADL they are only used at system level)
            for N : Taste_Node of CV.Deployment.Nodes loop
697 698 699 700 701 702 703 704
               --  Check that there if there are drivers, there is only one
               --  partition in the node as the current design does not specify
               --  what partition(s) use the drivers.
               if not N.Drivers.Is_Empty and N.Partitions.Length > 1 then
                  raise Concurrency_View_Error with
                    "Drivers in multi-partition systems are not supported";
               end if;

705 706 707 708 709 710 711 712 713 714 715 716 717 718
               for D : Taste_Device_Driver of N.Drivers loop
                  declare
                     Dot : constant Natural := Index (D.Name, ".");
                     Name : constant String := To_String (D.Name);
                     Result : constant String :=
                       (if Dot > 0
                        then Name (Name'First .. Dot - 1)
                        else "ERROR_MALFORMED_DEVICE_NAME");
                  begin
                     --  Device names are in the form ethernet0.other
                     --  Get rid of the ".other"
                     Device_Names := Device_Names & Result;
                  end;
                  Device_Node_Name  := Device_Node_Name & N.Name;
719 720
                  Device_Partition_Name :=  -- There must be only one
                    Device_Partition_Name & N.Partitions.First_Element.Name;
721 722 723 724 725 726 727 728 729 730 731 732 733 734
                  Device_AADL_Pkg   := Device_AADL_Pkg & D.Package_Name;
                  Device_Classifier := Device_Classifier & D.Device_Classifier;
                  Device_CPU := Device_CPU & D.Associated_Processor_Name;
                  Device_Configuration :=
                    Device_Configuration & D.Device_Configuration;
                  Device_Accessed_Bus_Name :=
                    Device_Accessed_Bus_Name & D.Accessed_Bus_Name;
                  Device_Accessed_Port_Name :=
                    Device_Accessed_Port_Name & D.Accessed_Port_Name;
                  Device_ASN1_Filename :=
                    Device_ASN1_Filename & D.ASN1_Filename;
                  Device_ASN1_Typename :=
                    Device_ASN1_Typename & D.ASN1_Typename;
                  Device_ASN1_Module := Device_ASN1_Module & D.ASN1_Module;
735 736 737 738 739 740 741 742 743 744 745 746

                  --  Update list of types and files without duplicates
                  if not Unique_ASN1_Sorts_Set.Contains
                    (Strip_String (To_String (D.ASN1_Typename)))
                  then
                     Unique_ASN1_Sorts_Set.Insert
                       (Strip_String (To_String (D.ASN1_Typename)));
                     Unique_ASN1_Sorts := Unique_ASN1_Sorts & D.ASN1_Typename;
                     Unique_ASN1_Modules :=
                       Unique_ASN1_Modules & D.ASN1_Module;
                     Unique_ASN1_Files := Unique_ASN1_Files & D.ASN1_Filename;
                  end if;
747 748 749
               end loop;
            end loop;

Maxime Perrotin's avatar
Maxime Perrotin committed
750
            if Trig_Sys and File_Sys /= "" and Nodes /= "" then
Maxime Perrotin's avatar
Maxime Perrotin committed
751
               --  Generate from system.tmplt
Maxime Perrotin's avatar
Maxime Perrotin committed
752 753
               Set_Sys := CV.Configuration.To_Template
                 & Assoc ("Nodes",       Nodes)
754 755 756
                 & Assoc ("Node_Names",          Node_Names)
                 & Assoc ("Node_CPU",            Node_CPU)
                 & Assoc ("Node_CPU_Classifier", Node_CPU_Cls)
Maxime Perrotin's avatar
Maxime Perrotin committed
757
                 & Assoc ("Node_Major_Frame",    Node_Major_Frame)
Maxime Perrotin's avatar
Maxime Perrotin committed
758
                 & Assoc ("Node_Has_Memory",     Node_Has_Memory)
759 760 761
                 & Assoc ("Partition_Names",     Partition_Names)
                 & Assoc ("Partition_Node",      Partition_Node)
                 & Assoc ("Partition_CPU",       Partition_CPU)
Maxime Perrotin's avatar
Maxime Perrotin committed
762
                 & Assoc ("Partition_Duration",  Partition_Time)
Maxime Perrotin's avatar
Maxime Perrotin committed
763
                 & Assoc ("Partition_VP",        Partition_VP)
764 765 766
                 & Assoc ("Part_Source_Name",    Part_Source_Name)
                 & Assoc ("Part_Source_Port",    Part_Source_Port)
                 & Assoc ("Part_Dest_Name",      Part_Dest_Name)
767
                 & Assoc ("Part_Dest_Port",      Part_Dest_Port)
768 769
                 & Assoc ("Threads",             Threads)
                 & Assoc ("Thread_Names",        All_Thread_Names)
770
                 & Assoc ("Block_Names",         All_Block_Names)
Maxime Perrotin's avatar
Maxime Perrotin committed
771 772 773
                 & Assoc ("Target_Packages",     All_Target_Names)
                 & Assoc ("Bus_Names",           Bus_Names)
                 & Assoc ("Bus_AADL_Package",    Bus_AADL_Pkg)
774 775 776
                 & Assoc ("Bus_Classifier",      Bus_Classifier)
                 & Assoc ("Device_Names",        Device_Names)
                 & Assoc ("Device_Node_Name",    Device_Node_Name)
777
                 & Assoc ("Device_Partition",    Device_Partition_Name)
778 779 780 781 782 783 784 785
                 & Assoc ("Device_AADL_Pkg",     Device_AADL_Pkg)
                 & Assoc ("Device_Classifier",   Device_Classifier)
                 & Assoc ("Device_CPU",          Device_CPU)
                 & Assoc ("Device_Config",       Device_Configuration)
                 & Assoc ("Device_Bus_Name",     Device_Accessed_Bus_Name)
                 & Assoc ("Device_Port_Name",    Device_Accessed_Port_Name)
                 & Assoc ("Device_ASN1_File",    Device_ASN1_Filename)
                 & Assoc ("Device_ASN1_Sort",    Device_ASN1_Typename)
786
                 & Assoc ("Device_ASN1_Module",  Device_ASN1_Module)
787 788 789
                 & Assoc ("Unique_Dev_ASN1_Files", Unique_ASN1_Files)
                 & Assoc ("Unique_Dev_ASN1_Mod",   Unique_ASN1_Modules)
                 & Assoc ("Unique_Dev_ASN1_Sorts", Unique_ASN1_Sorts)
790 791 792
                 & Assoc ("Connect_From_Part",   Connect_From_Partition)
                 & Assoc ("Connect_Via_Bus",     Connect_Via_Bus)
                 & Assoc ("Connect_Port_Name",   Connect_Port_Name);
Maxime Perrotin's avatar
Maxime Perrotin committed
793 794 795 796 797 798 799
               Create_Path (CV_Out_Dir);
               Create (File => Output_File,
                       Mode => Out_File,
                       Name => CV_Out_Dir & File_Sys);
               Put_Line (Output_File, Parse (Tmpl_Sys, Set_Sys));
               Close (Output_File);
            end if;
Maxime Perrotin's avatar
Maxime Perrotin committed
800
         end;
Maxime Perrotin's avatar
Maxime Perrotin committed
801 802
         <<continue>>
      end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
803
      End_Search (ST);
804
   end Generate_Code;
Maxime Perrotin's avatar
Maxime Perrotin committed
805 806 807

   procedure Generate_CV (CV : Taste_Concurrency_View) is
   begin
808
      CV.Generate_Code;
Maxime Perrotin's avatar
Maxime Perrotin committed
809 810 811 812 813 814
   exception
      when Error : Concurrency_View_Error | Ada.IO_Exceptions.Name_Error =>
         Put_Error ("Concurrency View : "
                    & Ada.Exceptions.Exception_Message (Error));
         raise Quit_Taste;
   end Generate_CV;
Maxime Perrotin's avatar
Maxime Perrotin committed
815

816
end TASTE.Concurrency_View;