diff options
Diffstat (limited to 'src/synth/elab-vhdl_utils.adb')
-rw-r--r-- | src/synth/elab-vhdl_utils.adb | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/src/synth/elab-vhdl_utils.adb b/src/synth/elab-vhdl_utils.adb new file mode 100644 index 000000000..b3b6c1a60 --- /dev/null +++ b/src/synth/elab-vhdl_utils.adb @@ -0,0 +1,147 @@ +-- Utils for elaboration. +-- Copyright (C) 2022 Tristan Gingold +-- +-- This file is part of GHDL. +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <gnu.org/licenses>. + +with Types; use Types; +with Vhdl.Utils; use Vhdl.Utils; + +package body Elab.Vhdl_Utils is + function Association_Iterator_Build (Inter_Chain : Node; Assoc_Chain : Node) + return Association_Iterator_Init is + begin + return Association_Iterator_Init'(Kind => Association_Function, + Inter_Chain => Inter_Chain, + Assoc_Chain => Assoc_Chain); + end Association_Iterator_Build; + + function Association_Iterator_Build + (Inter_Chain : Node; Left : Node; Right : Node) + return Association_Iterator_Init is + begin + return Association_Iterator_Init'(Kind => Association_Operator, + Inter_Chain => Inter_Chain, + Left => Left, + Right => Right); + end Association_Iterator_Build; + + function Get_Iterator_Inter_Chain (Init : Association_Iterator_Init) + return Node is + begin + return Init.Inter_Chain; + end Get_Iterator_Inter_Chain; + + function Get_Iterator_Assoc_Chain (Init : Association_Iterator_Init) + return Node is + begin + return Init.Assoc_Chain; + end Get_Iterator_Assoc_Chain; + + procedure Association_Iterate_Init (Iterator : out Association_Iterator; + Init : Association_Iterator_Init) is + begin + case Init.Kind is + when Association_Function => + Iterator := (Kind => Association_Function, + Inter => Init.Inter_Chain, + First_Named_Assoc => Null_Node, + Assoc => Init.Assoc_Chain); + when Association_Operator => + Iterator := (Kind => Association_Operator, + Inter => Init.Inter_Chain, + Op1 => Init.Left, + Op2 => Init.Right); + end case; + end Association_Iterate_Init; + + -- Return the next association. + -- ASSOC can be: + -- * an Iir_Kind_Association_By_XXX node (normal case) + -- * Null_Iir if INTER is not associated (and has a default value). + -- * an expression (for operator association). + -- Associations are returned in the order of interfaces. + procedure Association_Iterate_Next (Iterator : in out Association_Iterator; + Inter : out Node; + Assoc : out Node) is + begin + -- Next interface. + Inter := Iterator.Inter; + + if Inter = Null_Node then + -- End of iterator. + Assoc := Null_Node; + return; + end if; + + -- Advance to the next interface for the next call. + Iterator.Inter := Get_Chain (Iterator.Inter); + + case Iterator.Kind is + when Association_Function => + if Iterator.First_Named_Assoc = Null_Node then + Assoc := Iterator.Assoc; + -- Still using association by position. + if Assoc = Null_Node then + -- No more associations, all open. + return; + end if; + if Get_Formal (Assoc) = Null_Node then + -- Still by position, update for the next call. + Iterator.Assoc := Get_Chain (Assoc); + return; + end if; + Iterator.First_Named_Assoc := Assoc; + end if; + + -- Search by name. + declare + Formal : Node; + begin + Assoc := Iterator.First_Named_Assoc; + while Assoc /= Null_Node loop + Formal := Get_Formal (Assoc); + if Formal = Null_Node then + pragma Assert (Get_Artificial_Flag (Assoc)); + Assoc := Null_Node; + return; + end if; + Formal := Get_Interface_Of_Formal (Formal); + + -- Compare by identifier, as INTER can be the generic + -- interface, while FORMAL is the instantiated one. + if Get_Identifier (Formal) = Get_Identifier (Inter) then + -- Found. + -- Optimize in case assocs are in order. + if Assoc = Iterator.First_Named_Assoc then + Iterator.First_Named_Assoc := Get_Chain (Assoc); + end if; + return; + end if; + Assoc := Get_Chain (Assoc); + end loop; + end; + + -- Not found: open association. + return; + + when Association_Operator => + Assoc := Iterator.Op1; + Iterator.Op1 := Iterator.Op2; + Iterator.Op2 := Null_Node; + end case; + end Association_Iterate_Next; + +end Elab.Vhdl_Utils; |