1--  Analysis for translation.
2--  Copyright (C) 2009 Tristan Gingold
3--
4--  This program is free software: you can redistribute it and/or modify
5--  it under the terms of the GNU General Public License as published by
6--  the Free Software Foundation, either version 2 of the License, or
7--  (at your option) any later version.
8--
9--  This program is distributed in the hope that it will be useful,
10--  but WITHOUT ANY WARRANTY; without even the implied warranty of
11--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12--  GNU General Public License for more details.
13--
14--  You should have received a copy of the GNU General Public License
15--  along with this program.  If not, see <gnu.org/licenses>.
16
17with Errorout;
18with Simple_IO;
19with Vhdl.Utils; use Vhdl.Utils;
20with Vhdl.Nodes_Walk; use Vhdl.Nodes_Walk;
21with Vhdl.Prints;
22with Vhdl.Errors; use Vhdl.Errors;
23
24package body Trans_Analyzes is
25   Driver_List : Iir_List;
26
27   Has_After : Boolean;
28
29   function Extract_Driver_Target (Target : Iir) return Walk_Status
30   is
31      Base : Iir;
32      Prefix : Iir;
33   begin
34      Base := Get_Object_Prefix (Target);
35      --  Assigment to subprogram interface does not create a driver.
36      if Get_Kind (Base) = Iir_Kind_Interface_Signal_Declaration
37        and then Is_Parameter (Base)
38      then
39         return Walk_Continue;
40      end if;
41
42      Prefix := Get_Longuest_Static_Prefix (Target);
43      Add_Element (Driver_List, Prefix);
44      if Has_After then
45         Set_After_Drivers_Flag (Base, True);
46      end if;
47      return Walk_Continue;
48   end Extract_Driver_Target;
49
50   --  Set Has_After to True iff WF requires a non-direct driver.
51   procedure Extract_Has_After (Wf : Iir) is
52   begin
53      --  Disconnect, or time expression.
54      if Wf = Null_Iir
55        or else Get_Chain (Wf) /= Null_Iir
56        or else Get_Time (Wf) /= Null_Iir
57        or else Get_Kind (Get_We_Value (Wf)) = Iir_Kind_Null_Literal
58      then
59         Has_After := True;
60      end if;
61   end Extract_Has_After;
62
63   function Extract_Driver_Stmt (Stmt : Iir) return Walk_Status
64   is
65      Status : Walk_Status;
66      pragma Unreferenced (Status);
67   begin
68      --  Clear Has_After.  It will be set to True if a signal assignment
69      --  has an delay expression or a null transaction.
70      --  (It is cleared for any statement, just to factorize code).
71      Has_After := False;
72
73      case Iir_Kinds_Sequential_Statement (Get_Kind (Stmt)) is
74         when Iir_Kind_Simple_Signal_Assignment_Statement =>
75            declare
76               Wf : constant Iir := Get_Waveform_Chain (Stmt);
77            begin
78               if Is_Null (Wf)
79                 or else Get_Kind (Wf) /= Iir_Kind_Unaffected_Waveform
80               then
81                  --  Not unaffected or implicit disconnect.
82                  Extract_Has_After (Wf);
83                  Status := Walk_Assignment_Target
84                    (Get_Target (Stmt), Extract_Driver_Target'Access);
85               end if;
86            end;
87         when Iir_Kind_Signal_Force_Assignment_Statement
88            | Iir_Kind_Signal_Release_Assignment_Statement =>
89            null;
90         when Iir_Kind_Conditional_Signal_Assignment_Statement =>
91            declare
92               Cond_Wf : Iir;
93               Wf : Iir;
94               Has_Drv : Boolean;
95            begin
96               Cond_Wf := Get_Conditional_Waveform_Chain (Stmt);
97               Has_Drv := False;
98               while Cond_Wf /= Null_Iir loop
99                  Wf := Get_Waveform_Chain (Cond_Wf);
100                  if Get_Kind (Wf) /= Iir_Kind_Unaffected_Waveform then
101                     --  Not unaffected
102                     Extract_Has_After (Wf);
103                     Has_Drv := True;
104                  end if;
105                  Cond_Wf := Get_Chain (Cond_Wf);
106               end loop;
107               if Has_Drv then
108                  Status := Walk_Assignment_Target
109                    (Get_Target (Stmt), Extract_Driver_Target'Access);
110               end if;
111            end;
112         when Iir_Kind_Selected_Waveform_Assignment_Statement =>
113            declare
114               Swf : Iir;
115               Wf : Iir;
116               Has_Drv : Boolean;
117            begin
118               Swf := Get_Selected_Waveform_Chain (Stmt);
119               Has_Drv := False;
120               while Swf /= Null_Iir loop
121                  if not Get_Same_Alternative_Flag (Swf) then
122                     Wf := Get_Associated_Chain (Swf);
123                     if Get_Kind (Wf) /= Iir_Kind_Unaffected_Waveform then
124                        --  Not unaffected
125                        Extract_Has_After (Wf);
126                        Has_Drv := True;
127                     end if;
128                  end if;
129                  Swf := Get_Chain (Swf);
130               end loop;
131               if Has_Drv then
132                  Status := Walk_Assignment_Target
133                    (Get_Target (Stmt), Extract_Driver_Target'Access);
134               end if;
135            end;
136         when Iir_Kind_Procedure_Call_Statement =>
137            declare
138               Call : constant Iir := Get_Procedure_Call (Stmt);
139               Assoc : Iir;
140               Formal : Iir;
141               Inter : Iir;
142            begin
143               --  Very pessimist.
144               Has_After := True;
145
146               Assoc := Get_Parameter_Association_Chain (Call);
147               Inter := Get_Interface_Declaration_Chain
148                 (Get_Implementation (Call));
149               while Assoc /= Null_Iir loop
150                  Formal := Get_Association_Interface (Assoc, Inter);
151                  if Get_Kind (Assoc)
152                    = Iir_Kind_Association_Element_By_Expression
153                    and then
154                    Get_Kind (Formal) = Iir_Kind_Interface_Signal_Declaration
155                    and then Get_Mode (Formal) /= Iir_In_Mode
156                  then
157                     Status := Extract_Driver_Target (Get_Actual (Assoc));
158                  end if;
159                  Next_Association_Interface (Assoc, Inter);
160               end loop;
161            end;
162         when Iir_Kind_Null_Statement
163           | Iir_Kind_Assertion_Statement
164           | Iir_Kind_Report_Statement
165           | Iir_Kind_Wait_Statement
166           | Iir_Kind_Return_Statement
167           | Iir_Kind_Next_Statement
168           | Iir_Kind_Exit_Statement
169           | Iir_Kind_Variable_Assignment_Statement
170           | Iir_Kind_Conditional_Variable_Assignment_Statement
171           | Iir_Kind_For_Loop_Statement
172           | Iir_Kind_While_Loop_Statement
173           | Iir_Kind_Case_Statement
174           | Iir_Kind_If_Statement
175           | Iir_Kind_Break_Statement =>
176            null;
177      end case;
178      return Walk_Continue;
179   end Extract_Driver_Stmt;
180
181   procedure Extract_Drivers_Sequential_Stmt_Chain (Chain : Iir)
182   is
183      Status : Walk_Status;
184      pragma Unreferenced (Status);
185   begin
186      Status := Walk_Sequential_Stmt_Chain (Chain, Extract_Driver_Stmt'Access);
187   end Extract_Drivers_Sequential_Stmt_Chain;
188
189   procedure Extract_Drivers_Declaration_Chain (Chain : Iir)
190   is
191      Decl : Iir := Chain;
192   begin
193      while Decl /= Null_Iir loop
194
195         --  Only procedures and impure functions may contain assignment.
196         if Get_Kind (Decl) = Iir_Kind_Procedure_Body
197           or else (Get_Kind (Decl) = Iir_Kind_Function_Body
198                    and then
199                      not Get_Pure_Flag (Get_Subprogram_Specification (Decl)))
200         then
201            Extract_Drivers_Declaration_Chain (Get_Declaration_Chain (Decl));
202            Extract_Drivers_Sequential_Stmt_Chain
203              (Get_Sequential_Statement_Chain (Decl));
204         end if;
205
206         Decl := Get_Chain (Decl);
207      end loop;
208   end Extract_Drivers_Declaration_Chain;
209
210   function Extract_Drivers (Proc : Iir) return Iir_List
211   is
212   begin
213      Driver_List := Create_Iir_List;
214      Extract_Drivers_Declaration_Chain (Get_Declaration_Chain (Proc));
215      Extract_Drivers_Sequential_Stmt_Chain
216              (Get_Sequential_Statement_Chain (Proc));
217
218      return Driver_List;
219   end Extract_Drivers;
220
221   procedure Free_Drivers_List (List : in out Iir_List)
222   is
223      It : List_Iterator;
224   begin
225      It := List_Iterate (List);
226      while Is_Valid (It) loop
227         Set_After_Drivers_Flag (Get_Object_Prefix (Get_Element (It)), False);
228         Next (It);
229      end loop;
230      Destroy_Iir_List (List);
231   end Free_Drivers_List;
232
233   procedure Dump_Drivers (Proc : Iir; List : Iir_List)
234   is
235      use Simple_IO;
236      use Errorout;
237      El : Iir;
238      It : List_Iterator;
239   begin
240      Report_Msg (Msgid_Note, Semantic, +Proc,
241                  "List of drivers for %n:", (1 => +Proc));
242      Report_Msg (Msgid_Note, Semantic, +Proc,
243                  " (declared at %l)", (1 => +Proc));
244      It := List_Iterate (List);
245      while Is_Valid (It) loop
246         El := Get_Element (It);
247         if Get_After_Drivers_Flag (Get_Object_Prefix (El)) then
248            Put ("*  ");
249         else
250            Put ("   ");
251         end if;
252         Vhdl.Prints.Disp_Vhdl (El);
253         New_Line;
254         Next (It);
255      end loop;
256   end Dump_Drivers;
257
258end Trans_Analyzes;
259