taste-concurrency_view.adb 38.7 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
144
145
        T.PI.To_Template   --  Template of the PI used to create the thread
        & Assoc ("Thread_Name",       To_String (T.Name))
        & Assoc ("Entry_Port_Name",   To_String (T.Entry_Port_Name))
        & Assoc ("RCM",               To_String (T.RCM))
Maxime Perrotin's avatar
Maxime Perrotin committed
146
        & Assoc ("Need_Mutex",        T.Need_Mutex)
147
148
149
150
        & 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
151
        & Assoc ("RI_Port_Names",     RI_Port_Name)
152
153
154
        & 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
155
   end To_Template;
156

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

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

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

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

Maxime Perrotin's avatar
Maxime Perrotin committed
201
202
203
204
205
206
207
         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
208
         declare
Maxime Perrotin's avatar
Maxime Perrotin committed
209
210
            Path  : constant String  := Full_Name (Current);

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

236
237
238
239
240
241
242
243
244
245
               --  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
246
247
               --  Part_File_Name may contain a subfolder
               Subfolder       : Unbounded_String;
Maxime Perrotin's avatar
Maxime Perrotin committed
248
            begin
249
250
251
252
253
254
255
256
257
258
259
               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;
260
261
262
263
264
265
                  --  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;
266
267
               end loop;

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

                     --  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 "");
289
                  begin
290
                     Threads      := Threads & Newline & Result;
291
                     Part_Threads := Part_Threads & Newline & Result;
292
                     Thread_Names := Thread_Names & Name;
293
                     All_Thread_Names := All_Thread_Names & Name;
294
                     for P of T.Output_Ports loop
295
296
297
298
299
300
301
302
303
304
305
306
307
                        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;
308
                     end loop;
309
310
311
312
313
314
315
316
317
318
319
320
                     --  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;
321
                  end;
Maxime Perrotin's avatar
Maxime Perrotin committed
322
               end loop;
323

324
325
               for B of Partition.Blocks loop
                  declare
Maxime Perrotin's avatar
Maxime Perrotin committed
326
327
                     Block_Name   : constant String := To_String (B.Name);
                     Tmpl         : constant Block_As_Template :=
328
                       B.Prepare_Template;
Maxime Perrotin's avatar
Maxime Perrotin committed
329
330
331
332
333
                     Block_Assoc  : Translate_Set := Tmpl.Header;
                     Pro_PI_Tag   : Unbounded_String;
                     Unpro_PI_Tag : Unbounded_String;
                     RI_Tag       : Unbounded_String;
                     Result       : Unbounded_String;
334
335
336
337
338
339
340
341
342
343
344
345
346

                     --  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 "");
347
                  begin
348
                     Block_Names     := Block_Names & Block_Name;
349
                     All_Block_Names := All_Block_Names & Block_Name;
350
351
                     Block_Languages := Block_Languages & B.Language;

Maxime Perrotin's avatar
Maxime Perrotin committed
352
353
                     for PI_Assoc of Tmpl.Protected_Provided loop
                        Pro_PI_Tag := Pro_PI_Tag & Newline
354
355
356
                          & String'(Parse (Path & "/pi.tmplt",
                                    PI_Assoc & Assoc
                                      ("Partition_Name", Partition_Name)));
Maxime Perrotin's avatar
Maxime Perrotin committed
357
358
359
                     end loop;
                     for PI_Assoc of Tmpl.Unprotected_Provided loop
                        Unpro_PI_Tag := Unpro_PI_Tag & Newline
360
361
362
                          & String'(Parse (Path & "/pi.tmplt",
                                    PI_Assoc & Assoc
                                      ("Partition_Name", Partition_Name)));
363
364
                     end loop;
                     for RI_Assoc of Tmpl.Required loop
Maxime Perrotin's avatar
Maxime Perrotin committed
365
                        RI_Tag := RI_Tag & Newline
366
367
368
                          & String'(Parse (Path & "/ri.tmplt",
                                    RI_Assoc & Assoc
                                      ("Partition_Name", Partition_Name)));
369
                     end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
370
371
372

                     Block_Assoc :=
                       Join_Sets (Block_Assoc, CV.Configuration.To_Template)
Maxime Perrotin's avatar
Maxime Perrotin committed
373
374
375
                       & Assoc ("Protected_PIs",   Pro_PI_Tag)
                       & Assoc ("Unprotected_PIs", Unpro_PI_Tag)
                       & Assoc ("Required",        RI_Tag);
376

377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
                     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;
392
                  end;
Maxime Perrotin's avatar
Maxime Perrotin committed
393
               end loop;
394
395
396
               --  Association includes Name, Coverage, CPU Info, etc.
               --  (see taste-deployment_view.ads for the complete list)
               Partition_Assoc := Partition.Deployment_Partition.To_Template
397
                 & Assoc ("Threads",              Part_Threads)
398
399
400
401
402
403
404
405
406
407
                 & Assoc ("Thread_Names",         Thread_Names)
                 & 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)
408
409
                 & Assoc ("Part_Out_Port_Name",   Part_Out_Port_Names)
                 & Assoc ("Connected_Threads",    Connected_Threads)
410
411
412
413
                 & 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);
414

415
416
417
               All_Target_Names := All_Target_Names
                 & String'(Get (Get (Partition_Assoc, "Package_Name")));

418
419
420
421
422
423
               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
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
                  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));
440
441
442
443
444
445
446
447
448
                  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
449
            end Generate_Partition;
Maxime Perrotin's avatar
Maxime Perrotin committed
450

451
452
            --  Generate the code for one node
            function Generate_Node (Node_Name : String) return String is
453
454
455
               Partitions      : Unbounded_String;
               Partition_Names : Tag;
               Node_Assoc      : Translate_Set;
Maxime Perrotin's avatar
Maxime Perrotin committed
456
457
458
459
460
               --  Nodes may contain a list of virtual processors for TSP:
               VP_Names,
               VP_Package_Names,
               VP_Platforms,
               VP_Classifiers  : Vector_Tag;
461
            begin
Maxime Perrotin's avatar
Maxime Perrotin committed
462
               for Partition in CV.Nodes (Node_Name).Partitions.Iterate loop
463
464
                  Partition_Names := Partition_Names
                    & CV_Partitions.Key (Partition);
465
466
467
468
                  Partitions := Partitions & Newline
                    & Generate_Partition
                    (Partition_Name => CV_Partitions.Key (Partition),
                     Node_Name      => Node_Name);
Maxime Perrotin's avatar
Maxime Perrotin committed
469
               end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
470
471
472
473
474
475
476
               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
477
               Node_Assoc := +Assoc ("Partitions", Partitions)
478
                 & Assoc ("Partition_Names", Partition_Names)
Maxime Perrotin's avatar
Maxime Perrotin committed
479
480
                 & Assoc ("Has_Memory", Boolean'
                      (CV.Nodes (Node_Name).Deployment_Node.Memory.Name /= ""))
Maxime Perrotin's avatar
Maxime Perrotin committed
481
482
483
484
                 & Assoc ("VP_Names", VP_Names)
                 & Assoc ("VP_Package_Names", VP_Package_Names)
                 & Assoc ("VP_Platforms", VP_Platforms)
                 & Assoc ("VP_Classifiers", VP_Classifiers)
485
486
                 & Assoc ("Node_Name", Node_Name)
                 & Assoc ("CPU_Name",
Maxime Perrotin's avatar
Maxime Perrotin committed
487
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Name)
488
489
490
491
                 & Assoc ("CPU_Family",
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Family)
                 & Assoc ("CPU_Instance",
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Instance)
492
493
494
                 & Assoc ("CPU_Platform",
                         CV.Nodes (Node_Name).Deployment_Node.CPU_Platform'Img)
                 & Assoc ("CPU_Classifier",
Maxime Perrotin's avatar
Maxime Perrotin committed
495
496
497
                          CV.Nodes (Node_Name).Deployment_Node.CPU_Classifier)
                 & Assoc ("Package_Name",
                          CV.Nodes (Node_Name).Deployment_Node.Package_Name)
498
499
                 & Assoc ("Ada_Runtime",
                         CV.Nodes (Node_Name).Deployment_Node.Ada_Runtime);
500
501
               return Parse (Path & "/node.tmplt", Node_Assoc);
            end Generate_Node;
Maxime Perrotin's avatar
Maxime Perrotin committed
502

503
504
505
506
507
            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
508
              (if Valid_Dir then Strip_String (Parse (Tmpl_File)) else "");
509
510
            Trig_Sys        : constant Boolean := Exists (Tmpl_Sys);
            Set_Sys         : Translate_Set;
Maxime Perrotin's avatar
Maxime Perrotin committed
511
512
513
            Node_Names,                    --  List of nodes
            Node_CPU,                      --  Corresponding CPU name
            Node_CPU_Cls,                  --  Corresponding CPU classifier
Maxime Perrotin's avatar
Maxime Perrotin committed
514
515
            Node_Major_Frame,              --  Corresponding time frame (TSP)
            Node_Has_Memory : Vector_Tag;  --  Corresponding memory flag (TSP)
Maxime Perrotin's avatar
Maxime Perrotin committed
516
517
518
            Partition_Names,               --  List of partitions
            Partition_Node,                --  Corresponding node name
            Partition_CPU,                 --  Corresponding CPU name
Maxime Perrotin's avatar
Maxime Perrotin committed
519
            Partition_Time,                --  Corresponding TSP VP time
Maxime Perrotin's avatar
Maxime Perrotin committed
520
            Partition_VP    : Vector_Tag;  --  for TSP: VP binding
521
522
            Part_Source_Name,
            Part_Source_Port,
523
            Part_Dest_Port,
524
            Part_Dest_Name  : Vector_Tag;  -- Inter-partition connections (TSP)
Maxime Perrotin's avatar
Maxime Perrotin committed
525
526
527
            Bus_Names,
            Bus_AADL_Pkg,
            Bus_Classifier  : Vector_Tag;  --  System busses
528
529
            Device_Names,
            Device_Node_Name,
530
            Device_Partition_Name,
531
532
533
534
535
536
537
538
539
            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
540
541
542
543
544
545
546

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

547
548
549
550
            Connect_From_Partition,           --  Partition to bus connections
            Connect_Port_Name,
            Connect_Via_Bus    : Vector_Tag;
            Found : Boolean := False;
551
         begin
Maxime Perrotin's avatar
Maxime Perrotin committed
552
553
554
555
556
557
558
559
560
561
            --  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;

562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
            --  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
                       (To_String (BC.Dest_Function))
                     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 "
                    & To_String (BC.Dest_Function);
               end if;
            end loop;

591
592
593
            for Node in CV.Nodes.Iterate loop
               declare
                  Node_Name    : constant String := CV_Nodes.Key (Node);
Maxime Perrotin's avatar
Maxime Perrotin committed
594
                  Output_Dir   : constant String := CV_Out_Dir & Node_Name;
595
596
597
598
599
600
601
602
603
604
605
606
                  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 :=
607
608
                    (File_Name /= ""
                     and then Exists (Output_Dir & "/" & File_Name));
609

610
                  Trig_Tmpl    : constant Translate_Set :=
611
612
613
                    CV.Configuration.To_Template
                    & Assoc ("Filename_Is_Present", Present);

614
615
616
617
618
619
620
621
622
623
                  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
624
625

                     --  Associate node name, CPU name and CPU classifier
Maxime Perrotin's avatar
Maxime Perrotin committed
626
                     --  Also set flag if a memory region is defined
627
                     --  (this is needed for AADL backends)
Maxime Perrotin's avatar
Maxime Perrotin committed
628
                     Node_Names := Node_Names & Node_Name;
629
630
631
632
                     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
633
634
635
                     Node_Has_Memory := Node_Has_Memory
                       & (CV.Nodes (Node_Name)
                          .Deployment_Node.Memory.Name /= "");
Maxime Perrotin's avatar
Maxime Perrotin committed
636
637
                     Node_Major_Frame := Node_Major_Frame
                       & CV.Nodes (Node_Name).Deployment_Node.CPU_Duration;
638
639
640
641
642
643
644
645
646
647

                     --  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
648
649
650
                        Partition_VP := Partition_VP
                          & CV_Partitions.Element (Partition)
                          .Deployment_Partition.VP_Name;
651
                        Partition_Node := Partition_Node & Node_Name;
Maxime Perrotin's avatar
Maxime Perrotin committed
652
653
654
                        Partition_Time := Partition_Time
                          & CV_Partitions.Element (Partition)
                          .Deployment_Partition.VP_Duration;
655
656
657
658
659
660
661
662
663
664
665

                        --  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;
666
667
                           Part_Dest_Port := Part_Dest_Port
                             & Out_Port.Remote_Port_Name;
668
                        end loop;
669
670
671
                     end loop;

                     Nodes := Nodes & Newline & Node_Content;
672
673
674
675
676
677
678
679
680
681
682
                     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;
683
684
685
686
687
            --  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
688
689
690
691
692
693
694
695
               --  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;

696
697
698
699
700
701
702
703
704
705
706
707
708
709
               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;
710
711
                  Device_Partition_Name :=  -- There must be only one
                    Device_Partition_Name & N.Partitions.First_Element.Name;
712
713
714
715
716
717
718
719
720
721
722
723
724
725
                  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;
726
727
728
729
730
731
732
733
734
735
736
737

                  --  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;
738
739
740
               end loop;
            end loop;

Maxime Perrotin's avatar
Maxime Perrotin committed
741
            if Trig_Sys and File_Sys /= "" and Nodes /= "" then
Maxime Perrotin's avatar
Maxime Perrotin committed
742
               --  Generate from system.tmplt
Maxime Perrotin's avatar
Maxime Perrotin committed
743
744
               Set_Sys := CV.Configuration.To_Template
                 & Assoc ("Nodes",       Nodes)
745
746
747
                 & Assoc ("Node_Names",          Node_Names)
                 & Assoc ("Node_CPU",            Node_CPU)
                 & Assoc ("Node_CPU_Classifier", Node_CPU_Cls)
Maxime Perrotin's avatar
Maxime Perrotin committed
748
                 & Assoc ("Node_Major_Frame",    Node_Major_Frame)
Maxime Perrotin's avatar
Maxime Perrotin committed
749
                 & Assoc ("Node_Has_Memory",     Node_Has_Memory)
750
751
752
                 & Assoc ("Partition_Names",     Partition_Names)
                 & Assoc ("Partition_Node",      Partition_Node)
                 & Assoc ("Partition_CPU",       Partition_CPU)
Maxime Perrotin's avatar
Maxime Perrotin committed
753
                 & Assoc ("Partition_Duration",  Partition_Time)
Maxime Perrotin's avatar
Maxime Perrotin committed
754
                 & Assoc ("Partition_VP",        Partition_VP)
755
756
757
                 & Assoc ("Part_Source_Name",    Part_Source_Name)
                 & Assoc ("Part_Source_Port",    Part_Source_Port)
                 & Assoc ("Part_Dest_Name",      Part_Dest_Name)
758
                 & Assoc ("Part_Dest_Port",      Part_Dest_Port)
759
760
                 & Assoc ("Threads",             Threads)
                 & Assoc ("Thread_Names",        All_Thread_Names)
761
                 & Assoc ("Block_Names",         All_Block_Names)
Maxime Perrotin's avatar
Maxime Perrotin committed
762
763
764
                 & Assoc ("Target_Packages",     All_Target_Names)
                 & Assoc ("Bus_Names",           Bus_Names)
                 & Assoc ("Bus_AADL_Package",    Bus_AADL_Pkg)
765
766
767
                 & Assoc ("Bus_Classifier",      Bus_Classifier)
                 & Assoc ("Device_Names",        Device_Names)
                 & Assoc ("Device_Node_Name",    Device_Node_Name)
768
                 & Assoc ("Device_Partition",    Device_Partition_Name)
769
770
771
772
773
774
775
776
                 & 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)
777
                 & Assoc ("Device_ASN1_Module",  Device_ASN1_Module)
778
779
780
                 & Assoc ("Unique_Dev_ASN1_Files", Unique_ASN1_Files)
                 & Assoc ("Unique_Dev_ASN1_Mod",   Unique_ASN1_Modules)
                 & Assoc ("Unique_Dev_ASN1_Sorts", Unique_ASN1_Sorts)
781
782
783
                 & 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
784
785
786
787
788
789
790
               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
791
         end;
Maxime Perrotin's avatar
Maxime Perrotin committed
792
793
         <<continue>>
      end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
794
      End_Search (ST);
795
   end Generate_Code;
Maxime Perrotin's avatar
Maxime Perrotin committed
796
797
798

   procedure Generate_CV (CV : Taste_Concurrency_View) is
   begin
799
      CV.Generate_Code;
Maxime Perrotin's avatar
Maxime Perrotin committed
800
801
802
803
804
805
   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
806

807
end TASTE.Concurrency_View;