diff options
Diffstat (limited to 'src/synth/netlists-butils.adb')
-rw-r--r-- | src/synth/netlists-butils.adb | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/synth/netlists-butils.adb b/src/synth/netlists-butils.adb new file mode 100644 index 000000000..d26e1762c --- /dev/null +++ b/src/synth/netlists-butils.adb @@ -0,0 +1,142 @@ +-- Build utilities +-- Copyright (C) 2019 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, write to the Free Software +-- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +-- MA 02110-1301, USA. + +package body Netlists.Butils is + procedure Synth_Case (Ctxt : Context_Acc; + Sel : Net; + Els : in out Case_Element_Array; + Default : Net; + Res : out Net; + Sel_Loc : Syn_Src) + is + Wd : constant Width := Get_Width (Sel); + Mask : Uns64; + Sub_Sel : Net; + Lels : Natural; + Iels : Natural; + Oels : Natural; + begin + Lels := Els'Last; + Iels := Els'First; + + if Lels < Iels then + -- No choices + Res := Default; + return; + end if; + + -- Handle SEL bits by 2, so group case_element by 4. + for I in 1 .. Natural (Wd / 2) loop + -- Extract 2 bits from the selector. + Sub_Sel := Build_Extract (Ctxt, Sel, Width (2 * (I - 1)), 2); + Set_Location (Sub_Sel, Sel_Loc); + Mask := Shift_Left (not 0, Natural (2 * I)); + Iels := Els'First; + Oels := Els'First; + while Iels <= Lels loop + declare + type Net4 is array (0 .. 3) of Net; + G : Net4; + S_Group : constant Uns64 := Els (Iels).Sel and Mask; + S_El : Uns64; + El_Idx : Natural; + Rsel : Net; + begin + G := (others => Default); + for K in 0 .. 3 loop + exit when Iels > Lels; + S_El := Els (Iels).Sel; + exit when (S_El and Mask) /= S_Group; + El_Idx := Natural + (Shift_Right (S_El, Natural (2 * (I - 1))) and 3); + G (El_Idx) := Els (Iels).Val; + Iels := Iels + 1; + end loop; + if G (3) /= No_Net then + Rsel := Build_Mux4 (Ctxt, + Sub_Sel, G (0), G (1), G (2), G (3)); + Set_Location (Rsel, Sel_Loc); + elsif G (2) /= No_Net then + Rsel := Build_Mux2 + (Ctxt, + Build_Extract_Bit (Ctxt, Sel, Width (2 * (I - 1)) + 1), + Build_Mux2 (Ctxt, + Build_Extract_Bit (Ctxt, + Sel, Width (2 * (I - 1))), + G (0), G (1)), + G (2)); + Set_Location (Rsel, Sel_Loc); + elsif G (1) /= No_Net then + Rsel := Build_Mux2 + (Ctxt, + Build_Extract_Bit (Ctxt, + Sel, Width (2 * (I - 1))), + G (0), G (1)); + Set_Location (Rsel, Sel_Loc); + else + Rsel := G (0); + end if; + Els (Oels) := (Sel => S_Group, Val => Rsel); + Oels := Oels + 1; + end; + end loop; + Lels := Oels - 1; + end loop; + + -- If the width is not a multiple of 2, handle the last level. + if Wd mod 2 = 1 then + if Wd = 1 then + Sub_Sel := Sel; + else + Sub_Sel := Build_Extract_Bit (Ctxt, Sel, Wd - 1); + Set_Location (Sub_Sel, Sel_Loc); + end if; + Iels := Els'First; + Oels := Els'First; + while Iels <= Lels loop + declare + type Net2 is array (0 .. 1) of Net; + G : Net2; + S_Group : constant Uns64 := Els (Iels).Sel and Mask; + S_El : Uns64; + El_Idx : Natural; + Rsel : Net; + begin + G := (others => Default); + for K in 0 .. 1 loop + exit when Iels > Lels; + S_El := Els (Iels).Sel; + El_Idx := Natural + (Shift_Right (S_El, Natural (Wd - 1)) and 1); + G (El_Idx) := Els (Iels).Val; + Iels := Iels + 1; + end loop; + Rsel := Build_Mux2 (Ctxt, Sub_Sel, G (0), G (1)); + Set_Location (Rsel, Sel_Loc); + Els (Oels) := (Sel => S_Group, Val => Rsel); + Oels := Oels + 1; + end; + end loop; + Lels := Oels - 1; + end if; + pragma Assert (Lels = Els'First); + Res := Els (Els'First).Val; + end Synth_Case; +end Netlists.Butils; |