aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2020-09-19 09:52:35 +0200
committerTristan Gingold <tgingold@free.fr>2020-09-19 09:52:35 +0200
commit2fb5d3fa8e642f5f268f106a99af771e2076c8d2 (patch)
tree0e743920fa3e26d4c15617feeb83f7f142a681ff /src/synth
parent970afd54338ed04440c23a7b625f5c660e858cb2 (diff)
downloadghdl-2fb5d3fa8e642f5f268f106a99af771e2076c8d2.tar.gz
ghdl-2fb5d3fa8e642f5f268f106a99af771e2076c8d2.tar.bz2
ghdl-2fb5d3fa8e642f5f268f106a99af771e2076c8d2.zip
synth: handle find_leftmost/find_rigthmost. For #1460
Diffstat (limited to 'src/synth')
-rw-r--r--src/synth/synth-oper.adb77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/synth/synth-oper.adb b/src/synth/synth-oper.adb
index 26017042b..a3f7be688 100644
--- a/src/synth/synth-oper.adb
+++ b/src/synth/synth-oper.adb
@@ -1714,6 +1714,75 @@ package body Synth.Oper is
return Create_Value_Net (N, Create_Res_Bound (Left));
end Synth_Shift_Rotate;
+ function Synth_Find_Bit (Ctxt : Context_Acc;
+ Left, Right : Valtyp;
+ Res_Typ : Type_Acc;
+ Leftmost : Boolean;
+ Expr : Node) return Valtyp
+ is
+ pragma Assert (Left.Typ.Kind = Type_Vector);
+ Len : constant Uns32 := Left.Typ.Vbound.Len;
+ Max : Int32;
+ Rng : Discrete_Range_Type;
+ W : Uns32;
+ Typ : Type_Acc;
+ R_Net : Net;
+ L_Net : Net;
+ Res : Net;
+ begin
+ if Len = 0 then
+ return Create_Value_Int (-1, Res_Typ);
+ end if;
+
+ -- The intermediate result is computed using the least number of bits,
+ -- which must represent all positive values in the bounds using a
+ -- signed word (so that -1 is also represented).
+ Max := Int32'Max (Left.Typ.Vbound.Left, Left.Typ.Vbound.Right);
+ W := Utils.Clog2 (Uns32 (Max)) + 1;
+ Rng := (Dir => Dir_To,
+ Is_Signed => True,
+ Left => -1,
+ Right => Int64 (Max));
+ Typ := Create_Discrete_Type (Rng, Res_Typ.Sz, W);
+
+ R_Net := Get_Net (Ctxt, Right);
+ L_Net := Get_Net (Ctxt, Left);
+ Res := Build2_Const_Int (Ctxt, -1, W);
+ for I in 0 .. Len - 1 loop
+ declare
+ Pos : Uns32;
+ V : Int64;
+ Sel : Net;
+ begin
+ if Leftmost then
+ -- Iterate from the right to the left.
+ Pos := I;
+ if Left.Typ.Vbound.Dir = Dir_To then
+ V := Int64 (Left.Typ.Vbound.Right) - Int64 (I);
+ else
+ V := Int64 (Left.Typ.Vbound.Right) + Int64 (I);
+ end if;
+ else
+ Pos := Len - I - 1;
+ if Left.Typ.Vbound.Dir = Dir_To then
+ V := Int64 (Left.Typ.Vbound.Left) + Int64 (I);
+ else
+ V := Int64 (Left.Typ.Vbound.Left) - Int64 (I);
+ end if;
+ end if;
+ Sel := Build2_Compare (Ctxt, Id_Eq,
+ Build2_Extract (Ctxt, L_Net, Pos, 1),
+ R_Net);
+ Set_Location (Sel, Expr);
+ Res := Build_Mux2 (Ctxt, Sel, Res, Build2_Const_Int (Ctxt, V, W));
+ Set_Location (Res, Expr);
+ end;
+ end loop;
+
+ return Synth_Subtype_Conversion (Ctxt, Create_Value_Net (Res, Typ),
+ Res_Typ, False, Expr);
+ end Synth_Find_Bit;
+
function Synth_Dynamic_Predefined_Function_Call
(Subprg_Inst : Synth_Instance_Acc; Expr : Node) return Valtyp
is
@@ -1943,6 +2012,14 @@ package body Synth.Oper is
return Create_Value_Net (Res, Boolean_Type);
end if;
end;
+
+ when Iir_Predefined_Ieee_Numeric_Std_Find_Leftmost_Sgn
+ | Iir_Predefined_Ieee_Numeric_Std_Find_Leftmost_Uns =>
+ return Synth_Find_Bit (Ctxt, L, R, Res_Typ, True, Expr);
+ when Iir_Predefined_Ieee_Numeric_Std_Find_Rightmost_Sgn
+ | Iir_Predefined_Ieee_Numeric_Std_Find_Rightmost_Uns =>
+ return Synth_Find_Bit (Ctxt, L, R, Res_Typ, False, Expr);
+
when others =>
Error_Msg_Synth
(+Expr,