taste-concurrency_view.adb 41.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
     Ada.Characters.Latin_1,
9
10
     Ada.Strings.Fixed,
     TASTE.Backend;
Maxime Perrotin's avatar
Maxime Perrotin committed
11
12
13

use Ada.Directories;

14
15
package body TASTE.Concurrency_View is

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

18
   procedure Debug_Dump (CV : Taste_Concurrency_View; Output : File_Type) is
Maxime Perrotin's avatar
Maxime Perrotin committed
19
20
21
      procedure Dump_Partition (Partition : CV_Partition) is
      begin
         for Block of Partition.Blocks loop
22
23
24
            Put_Line (Output, "Protected Block : "
                      & To_String (Block.Ref_Function.Name));
            for Provided of Block.Block_Provided loop
Maxime Perrotin's avatar
Maxime Perrotin committed
25
26
               Put_Line (Output, " |_ PI : " & To_String (Provided.Name));
            end loop;
27
            for Required of Block.Ref_Function.Required loop
Maxime Perrotin's avatar
Maxime Perrotin committed
28
29
30
31
32
33
34
35
36
37
38
               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
39
                      (To_String (Block.Ref_Function.Name)).Unsafe_Just;
Maxime Perrotin's avatar
Maxime Perrotin committed
40
41
42
43
44
45
46
47
48
49
50
51
52
53
               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
54
         end loop;
55

Maxime Perrotin's avatar
Maxime Perrotin committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
         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
78
         end loop;
79
80
81
      end loop;
   end Debug_Dump;

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

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

108
      for RI of B.Ref_Function.Required loop
109
         Result.Required.Append (RI.Interface_To_Template
110
                                 & Assoc ("Calling_Threads", Calling_Threads));
111
112
      end loop;

113
      Result.Header := B.Ref_Function.Function_To_Template.Header
114
115
116
117
                       & Assoc ("Calling_Threads", Calling_Threads)
                       & Assoc ("Node_Name",       To_String (B.Node.Value_Or
                         (Taste_Node'(Name => US (""), others => <>)).Name));
      return Result;
118
   end Prepare_Block_Template;
119
120

   --  This function translates a thread definition into a template
Maxime Perrotin's avatar
Maxime Perrotin committed
121
   function To_Template (T : AADL_Thread) return Translate_Set is
122
      Remote_Thread    : Vector_Tag;
Maxime Perrotin's avatar
Maxime Perrotin committed
123
      RI_Port_Name     : Vector_Tag;  --  Name of the local RI (= port name)
124
125
126
      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
127
128
   begin
      for Out_Port of T.Output_Ports loop
Maxime Perrotin's avatar
Maxime Perrotin committed
129
         RI_Port_Name  := RI_Port_Name & Out_Port.Name;
130
131
         Remote_Thread := Remote_Thread & To_String (Out_Port.Remote_Thread);
         Remote_PI     := Remote_PI     & To_String (Out_Port.Remote_PI);
132
133
134
135
136
137
138
139
140
141
         --  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;
142
143
144
      end loop;

      return Result : constant Translate_Set :=
145
        T.PI.Interface_To_Template  --  PI used to create the thread
146
        & Assoc ("Thread_Name",       To_String (T.Name))
147
        & Assoc ("Partition_Name",    To_String (T.Partition_Name))
148
149
        & Assoc ("Entry_Port_Name",   To_String (T.Entry_Port_Name))
        & Assoc ("RCM",               To_String (T.RCM))
Maxime Perrotin's avatar
Maxime Perrotin committed
150
        & Assoc ("Need_Mutex",        T.Need_Mutex)
151
152
153
154
        & 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
155
        & Assoc ("RI_Port_Names",     RI_Port_Name)
156
157
158
        & 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
159
   end To_Template;
160

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

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

      --  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)
181
      All_Block_Names  : Tag;  --  Complete list of blocks
182
   begin
183
      Put_Debug ("Concurrency View templates expected in " & Prefix);
Maxime Perrotin's avatar
Maxime Perrotin committed
184
185
186
187
188
189
190
191
192
193
194
195
196
      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;

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

Maxime Perrotin's avatar
Maxime Perrotin committed
205
206
207
208
209
210
211
         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
212
         declare
Maxime Perrotin's avatar
Maxime Perrotin committed
213
214
            Path  : constant String  := Full_Name (Current);

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

242
243
244
245
246
247
248
249
250
251
               --  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
252
253
               --  Part_File_Name may contain a subfolder
               Subfolder       : Unbounded_String;
Maxime Perrotin's avatar
Maxime Perrotin committed
254
            begin
255
256
               Document_Template
                 (Templates_Concurrency_View_Sub_File_Part, Part_Tag);
257
258
259
260
261
262
263
264
265
266
267
               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;
268
269
270
271
272
273
                  --  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;
274
275
               end loop;

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

                     --  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 "");
297
                  begin
298
299
300
301
302
                     Document_Template
                       (Templates_Concurrency_View_Sub_Thread, Thread_Assoc);
                     Document_Template
                       (Templates_Concurrency_View_Sub_File_Thread,
                        Thread_Tag);
303

304
                     Threads      := Threads & Newline & Result;
305
                     Part_Threads := Part_Threads & Newline & Result;
306
                     Thread_Names := Thread_Names & Name;
307
308
309
310
311
312
                     --  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);

313
                     All_Thread_Names := All_Thread_Names & Name;
314
                     for P of T.Output_Ports loop
315
316
317
318
319
320
321
322
323
324
325
326
327
                        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;
328
                     end loop;
329
330
331
332
333
334
335
336
337
338
339
340
                     --  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;
341
                  end;
Maxime Perrotin's avatar
Maxime Perrotin committed
342
               end loop;
343

344
345
               for B of Partition.Blocks loop
                  declare
346
347
                     Block_Name   : constant String :=
                       To_String (B.Ref_Function.Name);
Maxime Perrotin's avatar
Maxime Perrotin committed
348
                     Tmpl         : constant Block_As_Template :=
349
                       B.Prepare_Block_Template;
Maxime Perrotin's avatar
Maxime Perrotin committed
350
351
352
353
354
                     Block_Assoc  : Translate_Set := Tmpl.Header;
                     Pro_PI_Tag   : Unbounded_String;
                     Unpro_PI_Tag : Unbounded_String;
                     RI_Tag       : Unbounded_String;
                     Result       : Unbounded_String;
355
356
357
358
359
360
361
362

                     --  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 :=
363
                       +Assoc ("Block_Name", Block_Name);
364
365
366
367
                     Block_File_Name : constant String :=
                       (if Block_Check
                        then Strip_String (Parse (Block_File_Id, Block_Tag))
                        else "");
368
                  begin
369
370
                     Document_Template
                       (Templates_Concurrency_View_Sub_File_Block, Block_Tag);
371
                     Block_Names     := Block_Names & Block_Name;
372
                     All_Block_Names := All_Block_Names & Block_Name;
373
374
                     Block_Languages := Block_Languages
                       & TASTE.Backend.Language_Spelling (B.Ref_Function);
375
376
                     Block_Instance_Of := Block_Instance_Of
                       & B.Ref_Function.Instance_Of.Value_Or (US (""));
377

Maxime Perrotin's avatar
Maxime Perrotin committed
378
                     for PI_Assoc of Tmpl.Protected_Provided loop
379
                        Document_Template
380
                          (Templates_Concurrency_View_Sub_PI,
381
                           PI_Assoc & Assoc ("Partition_Name", ""));
Maxime Perrotin's avatar
Maxime Perrotin committed
382
                        Pro_PI_Tag := Pro_PI_Tag & Newline
383
384
385
                          & String'(Parse (Path & "/pi.tmplt",
                                    PI_Assoc & Assoc
                                      ("Partition_Name", Partition_Name)));
Maxime Perrotin's avatar
Maxime Perrotin committed
386
387
388
                     end loop;
                     for PI_Assoc of Tmpl.Unprotected_Provided loop
                        Unpro_PI_Tag := Unpro_PI_Tag & Newline
389
390
391
                          & String'(Parse (Path & "/pi.tmplt",
                                    PI_Assoc & Assoc
                                      ("Partition_Name", Partition_Name)));
392
393
                     end loop;
                     for RI_Assoc of Tmpl.Required loop
394
                        Document_Template
395
                          (Templates_Concurrency_View_Sub_RI,
396
397
                           RI_Assoc & Assoc ("Partition_Name", ""));

Maxime Perrotin's avatar
Maxime Perrotin committed
398
                        RI_Tag := RI_Tag & Newline
399
400
401
                          & String'(Parse (Path & "/ri.tmplt",
                                    RI_Assoc & Assoc
                                      ("Partition_Name", Partition_Name)));
402
                     end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
403
404
405

                     Block_Assoc :=
                       Join_Sets (Block_Assoc, CV.Configuration.To_Template)
406
407
                       & Assoc ("Partition_Name",
                                Partition.Deployment_Partition.Name)
Maxime Perrotin's avatar
Maxime Perrotin committed
408
409
410
                       & Assoc ("Protected_PIs",   Pro_PI_Tag)
                       & Assoc ("Unprotected_PIs", Unpro_PI_Tag)
                       & Assoc ("Required",        RI_Tag);
411

412
                     Result := Parse (Path & "/block.tmplt", Block_Assoc);
413
414
                     Document_Template
                       (Templates_Concurrency_View_Sub_Block, Block_Assoc);
415
416
417
418
419
420
421
422
423
424
425
426
427
428

                     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;
429
                  end;
Maxime Perrotin's avatar
Maxime Perrotin committed
430
               end loop;
431
432
433
               --  Association includes Name, Coverage, CPU Info, etc.
               --  (see taste-deployment_view.ads for the complete list)
               Partition_Assoc := Partition.Deployment_Partition.To_Template
434
                 & Assoc ("Threads",              Part_Threads)
435
                 & Assoc ("Thread_Names",         Thread_Names)
436
                 & Assoc ("Thread_Has_Param",     Thread_Has_Param)
437
438
439
440
                 & Assoc ("Node_Name",            Node_Name)
                 & Assoc ("Blocks",               Blocks)
                 & Assoc ("Block_Names",          Block_Names)
                 & Assoc ("Block_Languages",      Block_Languages)
441
                 & Assoc ("Block_Instance_Of",    Block_Instance_Of)
442
443
444
445
446
                 & 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)
447
448
                 & Assoc ("Part_Out_Port_Name",   Part_Out_Port_Names)
                 & Assoc ("Connected_Threads",    Connected_Threads)
449
450
451
452
                 & 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);
453

454
455
456
               All_Target_Names := All_Target_Names
                 & String'(Get (Get (Partition_Assoc, "Package_Name")));

457
458
459
               Part_Content :=
                 Parse (Path & "/partition.tmplt", Partition_Assoc);

460
461
               Document_Template
                 (Templates_Concurrency_View_Sub_Partition, Partition_Assoc);
462

463
464
465
               --  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
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
                  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));
482
483
484
485
486
487
488
489
490
                  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
491
            end Generate_Partition;
Maxime Perrotin's avatar
Maxime Perrotin committed
492

493
494
            --  Generate the code for one node
            function Generate_Node (Node_Name : String) return String is
495
496
497
               Partitions      : Unbounded_String;
               Partition_Names : Tag;
               Node_Assoc      : Translate_Set;
Maxime Perrotin's avatar
Maxime Perrotin committed
498
499
500
501
502
               --  Nodes may contain a list of virtual processors for TSP:
               VP_Names,
               VP_Package_Names,
               VP_Platforms,
               VP_Classifiers  : Vector_Tag;
503
            begin
Maxime Perrotin's avatar
Maxime Perrotin committed
504
               for Partition in CV.Nodes (Node_Name).Partitions.Iterate loop
505
506
                  Partition_Names := Partition_Names
                    & CV_Partitions.Key (Partition);
507
508
509
510
                  Partitions := Partitions & Newline
                    & Generate_Partition
                    (Partition_Name => CV_Partitions.Key (Partition),
                     Node_Name      => Node_Name);
Maxime Perrotin's avatar
Maxime Perrotin committed
511
               end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
512
513
514
515
516
517
518
               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
519
               Node_Assoc := +Assoc ("Partitions", Partitions)
520
                 & Assoc ("Partition_Names", Partition_Names)
Maxime Perrotin's avatar
Maxime Perrotin committed
521
522
                 & Assoc ("Has_Memory", Boolean'
                      (CV.Nodes (Node_Name).Deployment_Node.Memory.Name /= ""))
Maxime Perrotin's avatar
Maxime Perrotin committed
523
524
525
526
                 & Assoc ("VP_Names", VP_Names)
                 & Assoc ("VP_Package_Names", VP_Package_Names)
                 & Assoc ("VP_Platforms", VP_Platforms)
                 & Assoc ("VP_Classifiers", VP_Classifiers)
527
528
                 & Assoc ("Node_Name", Node_Name)
                 & Assoc ("CPU_Name",
Maxime Perrotin's avatar
Maxime Perrotin committed
529
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Name)
530
531
532
533
                 & Assoc ("CPU_Family",
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Family)
                 & Assoc ("CPU_Instance",
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Instance)
534
535
536
                 & Assoc ("CPU_Platform",
                         CV.Nodes (Node_Name).Deployment_Node.CPU_Platform'Img)
                 & Assoc ("CPU_Classifier",
Maxime Perrotin's avatar
Maxime Perrotin committed
537
538
539
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Classifier)
                 & Assoc ("Package_Name",
                          CV.Nodes (Node_Name).Deployment_Node.Package_Name)
540
                 & Assoc ("Ada_Runtime",
541
                          CV.Nodes (Node_Name).Deployment_Node.Ada_Runtime);
542
543
               Document_Template
                 (Templates_Concurrency_View_Sub_Node, Node_Assoc);
544
545
               return Parse (Path & "/node.tmplt", Node_Assoc);
            end Generate_Node;
Maxime Perrotin's avatar
Maxime Perrotin committed
546

547
548
549
550
551
            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
552
              (if Valid_Dir then Strip_String (Parse (Tmpl_File)) else "");
553
554
            Trig_Sys        : constant Boolean := Exists (Tmpl_Sys);
            Set_Sys         : Translate_Set;
Maxime Perrotin's avatar
Maxime Perrotin committed
555
556
557
            Node_Names,                    --  List of nodes
            Node_CPU,                      --  Corresponding CPU name
            Node_CPU_Cls,                  --  Corresponding CPU classifier
Maxime Perrotin's avatar
Maxime Perrotin committed
558
559
            Node_Major_Frame,              --  Corresponding time frame (TSP)
            Node_Has_Memory : Vector_Tag;  --  Corresponding memory flag (TSP)
Maxime Perrotin's avatar
Maxime Perrotin committed
560
561
562
            Partition_Names,               --  List of partitions
            Partition_Node,                --  Corresponding node name
            Partition_CPU,                 --  Corresponding CPU name
Maxime Perrotin's avatar
Maxime Perrotin committed
563
            Partition_Time,                --  Corresponding TSP VP time
Maxime Perrotin's avatar
Maxime Perrotin committed
564
            Partition_VP    : Vector_Tag;  --  for TSP: VP binding
565
566
            Part_Source_Name,
            Part_Source_Port,
567
            Part_Dest_Port,
568
            Part_Dest_Name  : Vector_Tag;  -- Inter-partition connections (TSP)
Maxime Perrotin's avatar
Maxime Perrotin committed
569
570
571
            Bus_Names,
            Bus_AADL_Pkg,
            Bus_Classifier  : Vector_Tag;  --  System busses
572
573
            Device_Names,
            Device_Node_Name,
574
            Device_Partition_Name,
575
576
577
578
579
580
581
582
583
            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
584
585
586
587
588
589
590

            --  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;

591
592
593
594
            Connect_From_Partition,           --  Partition to bus connections
            Connect_Port_Name,
            Connect_Via_Bus    : Vector_Tag;
            Found : Boolean := False;
595
         begin
Maxime Perrotin's avatar
Maxime Perrotin committed
596
597
598
599
600
601
602
603
604
605
            --  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;

606
607
608
609
610
611
            --  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
612
               Connect_Via_Bus   := Connect_Via_Bus   & BC.Bus_Name;
613
614
615
616
617
618
619
               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
620
                       (To_String (BC.Source_Function))
621
622
623
624
625
626
627
628
629
630
                     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 "
631
                    & To_String (BC.Source_Function);
632
633
634
               end if;
            end loop;

635
636
637
            for Node in CV.Nodes.Iterate loop
               declare
                  Node_Name    : constant String := CV_Nodes.Key (Node);
Maxime Perrotin's avatar
Maxime Perrotin committed
638
                  Output_Dir   : constant String := CV_Out_Dir & Node_Name;
639
640
641
642
643
644
645
646
647
648
649
650
                  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 :=
651
652
                    (File_Name /= ""
                     and then Exists (Output_Dir & "/" & File_Name));
653

654
                  Trig_Tmpl    : constant Translate_Set :=
655
656
657
                    CV.Configuration.To_Template
                    & Assoc ("Filename_Is_Present", Present);

658
659
660
661
662
663
664
665
666
                  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
667
668
669
670
                  Document_Template
                    (Templates_Concurrency_View_Sub_File_Node, Filename_Set);
                  Document_Template
                    (Templates_Concurrency_View_Sub_Trigger, Trig_Tmpl);
671
                  if Trigger then
672
673

                     --  Associate node name, CPU name and CPU classifier
Maxime Perrotin's avatar
Maxime Perrotin committed
674
                     --  Also set flag if a memory region is defined
675
                     --  (this is needed for AADL backends)
Maxime Perrotin's avatar
Maxime Perrotin committed
676
                     Node_Names := Node_Names & Node_Name;
677
678
679
680
                     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
681
682
683
                     Node_Has_Memory := Node_Has_Memory
                       & (CV.Nodes (Node_Name)
                          .Deployment_Node.Memory.Name /= "");
Maxime Perrotin's avatar
Maxime Perrotin committed
684
685
                     Node_Major_Frame := Node_Major_Frame
                       & CV.Nodes (Node_Name).Deployment_Node.CPU_Duration;
686
687
688
689
690
691
692
693
694
695

                     --  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
696
697
698
                        Partition_VP := Partition_VP
                          & CV_Partitions.Element (Partition)
                          .Deployment_Partition.VP_Name;
699
                        Partition_Node := Partition_Node & Node_Name;
Maxime Perrotin's avatar
Maxime Perrotin committed
700
701
702
                        Partition_Time := Partition_Time
                          & CV_Partitions.Element (Partition)
                          .Deployment_Partition.VP_Duration;
703
704
705
706
707
708
709
710
711
712
713

                        --  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;
714
715
                           Part_Dest_Port := Part_Dest_Port
                             & Out_Port.Remote_Port_Name;
716
                        end loop;
717
718
719
                     end loop;

                     Nodes := Nodes & Newline & Node_Content;
720
721
722
723
724
725
726
727
728
729
730
                     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;
731
732
733
734
735
            --  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
736
737
738
739
740
741
742
743
               --  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;

744
745
746
747
748
749
750
751
752
753
754
755
756
757
               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;
758
759
                  Device_Partition_Name :=  -- There must be only one
                    Device_Partition_Name & N.Partitions.First_Element.Name;
760
761
762
763
764
765
766
767
768
769
770
771
772
773
                  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;
774
775
776
777
778
779
780
781
782
783
784
785

                  --  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;
786
787
788
               end loop;
            end loop;

Maxime Perrotin's avatar
Maxime Perrotin committed
789
            if Trig_Sys and File_Sys /= "" and Nodes /= "" then
Maxime Perrotin's avatar
Maxime Perrotin committed
790
               --  Generate from system.tmplt
Maxime Perrotin's avatar
Maxime Perrotin committed
791
792
               Set_Sys := CV.Configuration.To_Template
                 & Assoc ("Nodes",       Nodes)
793
794
795
                 & Assoc ("Node_Names",          Node_Names)
                 & Assoc ("Node_CPU",            Node_CPU)
                 & Assoc ("Node_CPU_Classifier", Node_CPU_Cls)
Maxime Perrotin's avatar
Maxime Perrotin committed
796
                 & Assoc ("Node_Major_Frame",    Node_Major_Frame)
Maxime Perrotin's avatar
Maxime Perrotin committed
797
                 & Assoc ("Node_Has_Memory",     Node_Has_Memory)
798
799
800
                 & Assoc ("Partition_Names",     Partition_Names)
                 & Assoc ("Partition_Node",      Partition_Node)
                 & Assoc ("Partition_CPU",       Partition_CPU)
Maxime Perrotin's avatar
Maxime Perrotin committed
801
                 & Assoc ("Partition_Duration",  Partition_Time)
Maxime Perrotin's avatar
Maxime Perrotin committed
802
                 & Assoc ("Partition_VP",        Partition_VP)
803
804
805
                 & Assoc ("Part_Source_Name",    Part_Source_Name)
                 & Assoc ("Part_Source_Port",    Part_Source_Port)
                 & Assoc ("Part_Dest_Name",      Part_Dest_Name)
806
                 & Assoc ("Part_Dest_Port",      Part_Dest_Port)
807
808
                 & Assoc ("Threads",             Threads)
                 & Assoc ("Thread_Names",        All_Thread_Names)
809
                 & Assoc ("Block_Names",         All_Block_Names)
Maxime Perrotin's avatar
Maxime Perrotin committed
810
811
812
                 & Assoc ("Target_Packages",     All_Target_Names)
                 & Assoc ("Bus_Names",           Bus_Names)
                 & Assoc ("Bus_AADL_Package",    Bus_AADL_Pkg)
813
814
815
                 & Assoc ("Bus_Classifier",      Bus_Classifier)
                 & Assoc ("Device_Names",        Device_Names)
                 & Assoc ("Device_Node_Name",    Device_Node_Name)
816
                 & Assoc ("Device_Partition",    Device_Partition_Name)
817
818
819
820
821
822
823
824
                 & 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)
825
                 & Assoc ("Device_ASN1_Module",  Device_ASN1_Module)
826
827
828
                 & Assoc ("Unique_Dev_ASN1_Files", Unique_ASN1_Files)
                 & Assoc ("Unique_Dev_ASN1_Mod",   Unique_ASN1_Modules)
                 & Assoc ("Unique_Dev_ASN1_Sorts", Unique_ASN1_Sorts)
829
830
831
                 & 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
832
833
834
835
836
               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));
837
838
               Document_Template
                 (Templates_Concurrency_View_Sub_System, Set_Sys);
Maxime Perrotin's avatar
Maxime Perrotin committed
839
840
               Close (Output_File);
            end if;
Maxime Perrotin's avatar
Maxime Perrotin committed
841
         end;
Maxime Perrotin's avatar
Maxime Perrotin committed
842
843
         <<continue>>
      end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
844
      End_Search (ST);
845
   end Generate_Code;
Maxime Perrotin's avatar
Maxime Perrotin committed
846
847
848

   procedure Generate_CV (CV : Taste_Concurrency_View) is
   begin
849
      CV.Generate_Code;
Maxime Perrotin's avatar
Maxime Perrotin committed
850
851
852
853
854
855
   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
856

857
end TASTE.Concurrency_View;