From 0875ce87c2e565023a350faf444ca2b3e3477ec7 Mon Sep 17 00:00:00 2001 From: Tristan Gingold Date: Fri, 3 Jun 2022 08:32:59 +0200 Subject: synth-vhdl_eval: handle more operations --- src/synth/synth-ieee-numeric_std.adb | 270 ++++++++++++++++++++++++++++++++++- src/synth/synth-ieee-numeric_std.ads | 17 +++ src/synth/synth-vhdl_eval.adb | 101 ++++++++++++- 3 files changed, 384 insertions(+), 4 deletions(-) diff --git a/src/synth/synth-ieee-numeric_std.adb b/src/synth/synth-ieee-numeric_std.adb index 7f5d0cbf2..d23b4e858 100644 --- a/src/synth/synth-ieee-numeric_std.adb +++ b/src/synth/synth-ieee-numeric_std.adb @@ -920,7 +920,7 @@ package body Synth.Ieee.Numeric_Std is Dlen : constant Uns32 := Dem.Typ.Abound.Len; pragma Assert (Nlen > 0); pragma Assert (Dlen > 0); - pragma Assert (Quot.Typ.Abound.Len = Nlen); + pragma Assert (Quot.Typ = null or else Quot.Typ.Abound.Len = Nlen); Reg : Std_Logic_Vector_Type (0 .. Dlen); Sub : Std_Logic_Vector_Type (0 .. Dlen - 1); Carry : Sl_X01; @@ -944,7 +944,9 @@ package body Synth.Ieee.Numeric_Std is -- Extra REG bit. Carry := Compute_Carry (Carry, Reg (0), '1'); -- Test - Write_Std_Logic (Quot.Mem, I, Carry); + if Quot.Mem /= null then + Write_Std_Logic (Quot.Mem, I, Carry); + end if; if Carry = '1' then Reg (0) := '0'; Reg (1 .. Dlen) := Sub; @@ -1003,6 +1005,28 @@ package body Synth.Ieee.Numeric_Std is return Quot; end Div_Uns_Uns; + function Div_Uns_Nat (L : Memtyp; R : Uns64; Loc : Syn_Src) return Memtyp + is + Rv : Memtyp; + begin + if L.Typ.Abound.Len = 0 then + return Create_Memory (L.Typ); -- FIXME: typ + end if; + Rv := To_Unsigned (R, L.Typ); + return Div_Uns_Uns (L, Rv, Loc); + end Div_Uns_Nat; + + function Div_Nat_Uns (L : Uns64; R : Memtyp; Loc : Syn_Src) return Memtyp + is + Lv : Memtyp; + begin + if R.Typ.Abound.Len = 0 then + return Create_Memory (R.Typ); -- FIXME: typ + end if; + Lv := To_Unsigned (L, R.Typ); + return Div_Uns_Uns (Lv, R, Loc); + end Div_Nat_Uns; + function Div_Sgn_Sgn (L, R : Memtyp; Loc : Syn_Src) return Memtyp is Nlen : constant Uns32 := L.Typ.Abound.Len; @@ -1057,4 +1081,246 @@ package body Synth.Ieee.Numeric_Std is return Quot; end Div_Sgn_Sgn; + function Div_Sgn_Int (L : Memtyp; R : Int64; Loc : Syn_Src) return Memtyp + is + Rv : Memtyp; + begin + if L.Typ.Abound.Len = 0 then + return Create_Memory (L.Typ); -- FIXME: typ + end if; + Rv := To_Signed (R, L.Typ); + return Div_Sgn_Sgn (L, Rv, Loc); + end Div_Sgn_Int; + + function Div_Int_Sgn (L : Int64; R : Memtyp; Loc : Syn_Src) return Memtyp + is + Lv : Memtyp; + begin + if R.Typ.Abound.Len = 0 then + return Create_Memory (R.Typ); -- FIXME: typ + end if; + Lv := To_Signed (L, R.Typ); + return Div_Sgn_Sgn (Lv, R, Loc); + end Div_Int_Sgn; + + function Rem_Uns_Uns (L, R : Memtyp; Loc : Syn_Src) return Memtyp + is + Nlen : constant Uns32 := L.Typ.Abound.Len; + Dlen : constant Uns32 := R.Typ.Abound.Len; + Rema : Memtyp; + R0 : Sl_X01; + begin + Rema.Typ := Create_Res_Type (R.Typ, Dlen); + Rema := Create_Memory (Rema.Typ); + if Nlen = 0 or Dlen = 0 then + return Rema; + end if; + + R0 := Has_0x (R); + if Has_0x (L) = 'X' or R0 = 'X' then + Warning_Msg_Synth + (+Loc, "NUMERIC_STD.""rem"": non logical value detected"); + Fill (Rema, 'X'); + return Rema; + end if; + if R0 = '0' then + Error_Msg_Synth (+Loc, "NUMERIC_STD.""rem"": division by 0"); + Fill (Rema, 'X'); + return Rema; + end if; + Divmod (L, R, Null_Memtyp, Rema); + return Rema; + end Rem_Uns_Uns; + + function Rem_Uns_Nat (L : Memtyp; R : Uns64; Loc : Syn_Src) return Memtyp + is + Rv : Memtyp; + begin + if L.Typ.Abound.Len = 0 then + return Create_Memory (L.Typ); -- FIXME: typ + end if; + Rv := To_Unsigned (R, L.Typ); + return Rem_Uns_Uns (L, Rv, Loc); + end Rem_Uns_Nat; + + function Rem_Nat_Uns (L : Uns64; R : Memtyp; Loc : Syn_Src) return Memtyp + is + Lv : Memtyp; + begin + if R.Typ.Abound.Len = 0 then + return Create_Memory (R.Typ); -- FIXME: typ + end if; + Lv := To_Unsigned (L, R.Typ); + return Rem_Uns_Uns (Lv, R, Loc); + end Rem_Nat_Uns; + + function Rem_Sgn_Sgn (L, R : Memtyp; Loc : Syn_Src) return Memtyp + is + Nlen : constant Uns32 := L.Typ.Abound.Len; + Dlen : constant Uns32 := R.Typ.Abound.Len; + Rema : Memtyp; + R0 : Sl_X01; + Lu : Memtyp; + Ru : Memtyp; + Neg : Boolean; + begin + Rema.Typ := Create_Res_Type (L.Typ, Dlen); + Rema := Create_Memory (Rema.Typ); + if Nlen = 0 or Dlen = 0 then + return Rema; + end if; + + R0 := Has_0x (R); + if Has_0x (L) = 'X' or R0 = 'X' then + Warning_Msg_Synth + (+Loc, "NUMERIC_STD.""rem"": non logical value detected"); + Fill (Rema, 'X'); + return Rema; + end if; + if R0 = '0' then + Error_Msg_Synth (+Loc, "NUMERIC_STD.""rem"": division by 0"); + Fill (Rema, 'X'); + return Rema; + end if; + + if To_X01 (Read_Std_Logic (L.Mem, 0)) = '1' then + Lu.Typ := L.Typ; + Lu.Mem := Neg_Vec_Notyp (L); + Neg := True; + else + Neg := False; + Lu := L; + end if; + + if To_X01 (Read_Std_Logic (R.Mem, 0)) = '1' then + Ru.Typ := R.Typ; + Ru.Mem := Neg_Vec_Notyp (R); + else + Ru := R; + end if; + + Divmod (Lu, Ru, Null_Memtyp, Rema); + + -- Result of rem has the sign of the dividend. + if Neg then + Neg_Vec (Rema); + end if; + return Rema; + end Rem_Sgn_Sgn; + + function Rem_Sgn_Int (L : Memtyp; R : Int64; Loc : Syn_Src) return Memtyp + is + Rv : Memtyp; + begin + if L.Typ.Abound.Len = 0 then + return Create_Memory (L.Typ); -- FIXME: typ + end if; + Rv := To_Signed (R, L.Typ); + return Rem_Sgn_Sgn (L, Rv, Loc); + end Rem_Sgn_Int; + + function Rem_Int_Sgn (L : Int64; R : Memtyp; Loc : Syn_Src) return Memtyp + is + Lv : Memtyp; + begin + if R.Typ.Abound.Len = 0 then + return Create_Memory (R.Typ); -- FIXME: typ + end if; + Lv := To_Signed (L, R.Typ); + return Rem_Sgn_Sgn (Lv, R, Loc); + end Rem_Int_Sgn; + + function Mod_Sgn_Sgn (L, R : Memtyp; Loc : Syn_Src) return Memtyp + is + Nlen : constant Uns32 := L.Typ.Abound.Len; + Dlen : constant Uns32 := R.Typ.Abound.Len; + Rema : Memtyp; + R0 : Sl_X01; + Lu : Memtyp; + Ru : Memtyp; + L_Neg, R_Neg : Boolean; + begin + Rema.Typ := Create_Res_Type (L.Typ, Dlen); + Rema := Create_Memory (Rema.Typ); + if Nlen = 0 or Dlen = 0 then + return Rema; + end if; + + R0 := Has_0x (R); + if Has_0x (L) = 'X' or R0 = 'X' then + Warning_Msg_Synth + (+Loc, "NUMERIC_STD.""rem"": non logical value detected"); + Fill (Rema, 'X'); + return Rema; + end if; + if R0 = '0' then + Error_Msg_Synth (+Loc, "NUMERIC_STD.""rem"": division by 0"); + Fill (Rema, 'X'); + return Rema; + end if; + + if To_X01 (Read_Std_Logic (L.Mem, 0)) = '1' then + Lu.Typ := L.Typ; + Lu.Mem := Neg_Vec_Notyp (L); + L_Neg := True; + else + Lu := L; + L_Neg := False; + end if; + + if To_X01 (Read_Std_Logic (R.Mem, 0)) = '1' then + Ru.Typ := R.Typ; + Ru.Mem := Neg_Vec_Notyp (R); + R_Neg := True; + else + Ru := R; + R_Neg := False; + end if; + + Divmod (Lu, Ru, Null_Memtyp, Rema); + + if Has_0x (Rema) = '0' then + -- If the remainder is 0, then the modulus is 0. + return Rema; + else + -- Result of rem has the sign of the divisor. + if R_Neg then + if L_Neg then + Neg_Vec (Rema); + return Rema; + else + return Add_Vec_Vec (R, Rema, True, Loc); + end if; + else + if L_Neg then + return Sub_Vec_Vec (R, Rema, True, Loc); + else + return Rema; + end if; + end if; + end if; + end Mod_Sgn_Sgn; + + function Mod_Sgn_Int (L : Memtyp; R : Int64; Loc : Syn_Src) return Memtyp + is + Rv : Memtyp; + begin + if L.Typ.Abound.Len = 0 then + return Create_Memory (L.Typ); -- FIXME: typ + end if; + Rv := To_Signed (R, L.Typ); + return Mod_Sgn_Sgn (L, Rv, Loc); + end Mod_Sgn_Int; + + function Mod_Int_Sgn (L : Int64; R : Memtyp; Loc : Syn_Src) return Memtyp + is + Lv : Memtyp; + begin + if R.Typ.Abound.Len = 0 then + return Create_Memory (R.Typ); -- FIXME: typ + end if; + Lv := To_Signed (L, R.Typ); + return Mod_Sgn_Sgn (Lv, R, Loc); + end Mod_Int_Sgn; + end Synth.Ieee.Numeric_Std; diff --git a/src/synth/synth-ieee-numeric_std.ads b/src/synth/synth-ieee-numeric_std.ads index 2d6ba68d5..884c8378f 100644 --- a/src/synth/synth-ieee-numeric_std.ads +++ b/src/synth/synth-ieee-numeric_std.ads @@ -64,7 +64,24 @@ package Synth.Ieee.Numeric_Std is -- "/" function Div_Uns_Uns (L, R : Memtyp; Loc : Syn_Src) return Memtyp; + function Div_Uns_Nat (L : Memtyp; R : Uns64; Loc : Syn_Src) return Memtyp; + function Div_Nat_Uns (L : Uns64; R : Memtyp; Loc : Syn_Src) return Memtyp; function Div_Sgn_Sgn (L, R : Memtyp; Loc : Syn_Src) return Memtyp; + function Div_Sgn_Int (L : Memtyp; R : Int64; Loc : Syn_Src) return Memtyp; + function Div_Int_Sgn (L : Int64; R : Memtyp; Loc : Syn_Src) return Memtyp; + + -- "rem" + function Rem_Uns_Uns (L, R : Memtyp; Loc : Syn_Src) return Memtyp; + function Rem_Uns_Nat (L : Memtyp; R : Uns64; Loc : Syn_Src) return Memtyp; + function Rem_Nat_Uns (L : Uns64; R : Memtyp; Loc : Syn_Src) return Memtyp; + function Rem_Sgn_Sgn (L, R : Memtyp; Loc : Syn_Src) return Memtyp; + function Rem_Sgn_Int (L : Memtyp; R : Int64; Loc : Syn_Src) return Memtyp; + function Rem_Int_Sgn (L : Int64; R : Memtyp; Loc : Syn_Src) return Memtyp; + + -- "mod" + function Mod_Sgn_Sgn (L, R : Memtyp; Loc : Syn_Src) return Memtyp; + function Mod_Sgn_Int (L : Memtyp; R : Int64; Loc : Syn_Src) return Memtyp; + function Mod_Int_Sgn (L : Int64; R : Memtyp; Loc : Syn_Src) return Memtyp; -- Shift function Shift_Vec (Val : Memtyp; diff --git a/src/synth/synth-vhdl_eval.adb b/src/synth/synth-vhdl_eval.adb index 4a45fb989..17d4548c8 100644 --- a/src/synth/synth-vhdl_eval.adb +++ b/src/synth/synth-vhdl_eval.adb @@ -953,7 +953,7 @@ package body Synth.Vhdl_Eval is declare Res : Boolean; begin - Res := Compare_Sgn_Sgn (Left, Right, Less, Expr) <= Equal; + Res := Compare_Sgn_Sgn (Left, Right, Greater, Expr) <= Equal; return Create_Memory_U8 (Boolean'Pos (Res), Res_Typ); end; @@ -982,7 +982,7 @@ package body Synth.Vhdl_Eval is declare Res : Boolean; begin - Res := Compare_Sgn_Sgn (Left, Right, Less, Expr) < Equal; + Res := Compare_Sgn_Sgn (Left, Right, Greater, Expr) < Equal; return Create_Memory_U8 (Boolean'Pos (Res), Res_Typ); end; @@ -1028,8 +1028,41 @@ package body Synth.Vhdl_Eval is when Iir_Predefined_Ieee_Numeric_Std_Div_Uns_Uns => return Div_Uns_Uns (Left, Right, Expr); + when Iir_Predefined_Ieee_Numeric_Std_Div_Uns_Nat => + return Div_Uns_Nat (Left, To_Uns64 (Read_Discrete (Right)), Expr); + when Iir_Predefined_Ieee_Numeric_Std_Div_Nat_Uns => + return Div_Nat_Uns (To_Uns64 (Read_Discrete (Left)), Right, Expr); + when Iir_Predefined_Ieee_Numeric_Std_Div_Sgn_Sgn => return Div_Sgn_Sgn (Left, Right, Expr); + when Iir_Predefined_Ieee_Numeric_Std_Div_Int_Sgn => + return Div_Int_Sgn (Read_Discrete (Left), Right, Expr); + when Iir_Predefined_Ieee_Numeric_Std_Div_Sgn_Int => + return Div_Sgn_Int (Left, Read_Discrete (Right), Expr); + + when Iir_Predefined_Ieee_Numeric_Std_Rem_Uns_Uns + | Iir_Predefined_Ieee_Numeric_Std_Mod_Uns_Uns => + return Rem_Uns_Uns (Left, Right, Expr); + when Iir_Predefined_Ieee_Numeric_Std_Rem_Uns_Nat + | Iir_Predefined_Ieee_Numeric_Std_Mod_Uns_Nat => + return Rem_Uns_Nat (Left, To_Uns64 (Read_Discrete (Right)), Expr); + when Iir_Predefined_Ieee_Numeric_Std_Rem_Nat_Uns + | Iir_Predefined_Ieee_Numeric_Std_Mod_Nat_Uns => + return Rem_Nat_Uns (To_Uns64 (Read_Discrete (Left)), Right, Expr); + + when Iir_Predefined_Ieee_Numeric_Std_Rem_Sgn_Sgn => + return Rem_Sgn_Sgn (Left, Right, Expr); + when Iir_Predefined_Ieee_Numeric_Std_Rem_Int_Sgn => + return Rem_Int_Sgn (Read_Discrete (Left), Right, Expr); + when Iir_Predefined_Ieee_Numeric_Std_Rem_Sgn_Int => + return Rem_Sgn_Int (Left, Read_Discrete (Right), Expr); + + when Iir_Predefined_Ieee_Numeric_Std_Mod_Sgn_Sgn => + return Mod_Sgn_Sgn (Left, Right, Expr); + when Iir_Predefined_Ieee_Numeric_Std_Mod_Int_Sgn => + return Mod_Int_Sgn (Read_Discrete (Left), Right, Expr); + when Iir_Predefined_Ieee_Numeric_Std_Mod_Sgn_Int => + return Mod_Sgn_Int (Left, Read_Discrete (Right), Expr); when Iir_Predefined_Ieee_Numeric_Std_Srl_Uns_Int | Iir_Predefined_Ieee_Numeric_Std_Srl_Sgn_Int => @@ -1574,6 +1607,58 @@ package body Synth.Vhdl_Eval is return String_To_Memtyp (Str, Res_Typ); end Eval_Bit_Vector_To_String; + function Eval_Logic_Vector_To_String (Val : Memtyp; + Res_Typ : Type_Acc; + Log_Base : Natural) return Memtyp + is + Base : constant Natural := 2 ** Log_Base; + Blen : constant Uns32 := Val.Typ.Abound.Len; + Str : String (1 .. (Natural (Blen) + Log_Base - 1) / Log_Base); + Pos : Natural; + D : Std_Ulogic; + V : Natural; + N : Natural; + Has_X, Has_Z, Has_D : Boolean; + begin + V := 0; + N := 1; + Has_X := False; + Has_Z := False; + Has_D := False; + Pos := Str'Last; + for I in 1 .. Blen loop + D := Read_Std_Logic (Val.Mem, Blen - I); + case D is + when '0' | 'L' => + Has_D := True; + when '1' | 'H' => + Has_D := True; + V := V + N; + when 'Z' | 'W' => + Has_Z := True; + when 'X' | 'U' | '-' => + Has_X := True; + end case; + N := N * 2; + if N = Base or else I = Blen then + if Has_X or (Has_Z and Has_D) then + Str (Pos) := 'X'; + elsif Has_Z then + Str (Pos) := 'Z'; + else + Str (Pos) := Hex_Chars (V); + end if; + Pos := Pos - 1; + N := 1; + V := 0; + Has_X := False; + Has_Z := False; + Has_D := False; + end if; + end loop; + return String_To_Memtyp (Str, Res_Typ); + end Eval_Logic_Vector_To_String; + function Eval_Static_Predefined_Function_Call (Param1 : Valtyp; Param2 : Valtyp; Res_Typ : Type_Acc; @@ -1862,6 +1947,18 @@ package body Synth.Vhdl_Eval is return Create_Memory_U8 (Boolean'Pos (B = 'X'), Res_Typ); end; + when Iir_Predefined_Ieee_1164_To_Stdlogicvector_Suv + | Iir_Predefined_Ieee_1164_To_Stdulogicvector_Slv => + -- TODO + return (Param1.Typ, Param1.Val.Mem); + + when Iir_Predefined_Ieee_1164_To_Hstring => + return Eval_Logic_Vector_To_String + (Get_Memtyp (Param1), Res_Typ, 4); + when Iir_Predefined_Ieee_1164_To_Ostring => + return Eval_Logic_Vector_To_String + (Get_Memtyp (Param1), Res_Typ, 3); + when Iir_Predefined_Ieee_Math_Real_Log2 => declare function Log2 (Arg : Fp64) return Fp64; -- cgit v1.2.3