diff options
Diffstat (limited to 'src/synth')
-rw-r--r-- | src/synth/synth-ieee-numeric_std.adb | 178 | ||||
-rw-r--r-- | src/synth/synth-ieee-numeric_std.ads | 4 | ||||
-rw-r--r-- | src/synth/synth-objtypes.ads | 1 | ||||
-rw-r--r-- | src/synth/synth-static_oper.adb | 5 |
4 files changed, 188 insertions, 0 deletions
diff --git a/src/synth/synth-ieee-numeric_std.adb b/src/synth/synth-ieee-numeric_std.adb index 60b1182cb..47e2e2a54 100644 --- a/src/synth/synth-ieee-numeric_std.adb +++ b/src/synth/synth-ieee-numeric_std.adb @@ -741,6 +741,38 @@ package body Synth.Ieee.Numeric_Std is return Mul_Sgn_Sgn (L, Rv, Loc); end Mul_Sgn_Int; + function Neg_Vec_Notyp (V : Memtyp) return Memory_Ptr + is + Len : constant Uns32 := V.Typ.Vbound.Len; + Vb, Carry : Sl_X01; + Res : Memory_Ptr; + begin + Res := Alloc_Memory (V.Typ); + + Carry := '1'; + for I in 1 .. Len loop + Vb := Sl_To_X01 (Read_Std_Logic (V.Mem, Len - I)); + Vb := Not_Table (Vb); + Write_Std_Logic (Res, Len - I, Xor_Table (Carry, Vb)); + Carry := And_Table (Carry, Vb); + end loop; + return Res; + end Neg_Vec_Notyp; + + procedure Neg_Vec (V : Memtyp) + is + Len : constant Uns32 := V.Typ.Vbound.Len; + Vb, Carry : Sl_X01; + begin + Carry := '1'; + for I in 1 .. Len loop + Vb := Sl_To_X01 (Read_Std_Logic (V.Mem, Len - I)); + Vb := Not_Table (Vb); + Write_Std_Logic (V.Mem, Len - I, Xor_Table (Carry, Vb)); + Carry := And_Table (Carry, Vb); + end loop; + end Neg_Vec; + function Neg_Vec (V : Memtyp; Loc : Syn_Src) return Memtyp is Len : constant Uns32 := V.Typ.Vbound.Len; @@ -821,4 +853,150 @@ package body Synth.Ieee.Numeric_Std is end if; return Res; end Shift_Vec; + + type Std_Logic_Vector_Type is array (Uns32 range <>) of Std_Ulogic; + + procedure Divmod (Num, Dem : Memtyp; Quot, Remain : Memtyp) + is + Nlen : constant Uns32 := Num.Typ.Vbound.Len; + Dlen : constant Uns32 := Dem.Typ.Vbound.Len; + pragma Assert (Nlen > 0); + pragma Assert (Dlen > 0); + pragma Assert (Quot.Typ.Vbound.Len = Nlen); + Reg : Std_Logic_Vector_Type (0 .. Dlen); + Sub : Std_Logic_Vector_Type (0 .. Dlen - 1); + Carry : Sl_X01; + D : Sl_X01; + begin + Reg := (others => '0'); + Sub := (others => '0'); + + -- Stupid pen and paper division algorithm. + for I in 0 .. Nlen - 1 loop + -- Shift + Reg (0 .. Dlen - 1) := Reg (1 .. Dlen); + Reg (Dlen) := Sl_To_X01 (Read_Std_Logic (Num.Mem, I)); + -- Substract + Carry := '1'; + for J in reverse 0 .. Dlen - 1 loop + D := Not_Table (Read_Std_Logic (Dem.Mem, J)); + Sub (J) := Compute_Sum (Carry, Reg (J + 1), D); + Carry := Compute_Carry (Carry, Reg (J + 1), D); + end loop; + -- Extra REG bit. + Carry := Compute_Carry (Carry, Reg (0), '1'); + -- Test + Write_Std_Logic (Quot.Mem, I, Carry); + if Carry = '1' then + Reg (0) := '0'; + Reg (1 .. Dlen) := Sub; + end if; + end loop; + if Remain /= Null_Memtyp then + pragma Assert (Remain.Typ.Vbound.Len = Dlen); + for I in 0 .. Dlen - 1 loop + Write_Std_Logic (Remain.Mem, I, Reg (I + 1)); + end loop; + end if; + end Divmod; + + function Has_0x (V : Memtyp) return Sl_X01 + is + Res : Sl_X01 := '0'; + E : Sl_X01; + begin + for I in 0 .. V.Typ.Vbound.Len - 1 loop + E := To_X01 (Read_Std_Logic (V.Mem, I)); + if E = 'X' then + return 'X'; + elsif E = '1' then + Res := '1'; + end if; + end loop; + return Res; + end Has_0x; + + function Div_Uns_Uns (L, R : Memtyp; Loc : Syn_Src) return Memtyp + is + Nlen : constant Uns32 := L.Typ.Vbound.Len; + Dlen : constant Uns32 := R.Typ.Vbound.Len; + Quot : Memtyp; + R0 : Sl_X01; + begin + Quot.Typ := Create_Res_Type (L.Typ, Nlen); + Quot := Create_Memory (Quot.Typ); + if Nlen = 0 or Dlen = 0 then + return Quot; + end if; + + R0 := Has_0x (R); + if Has_0x (L) = 'X' or R0 = 'X' then + Warning_Msg_Synth + (+Loc, "NUMERIC_STD.""/"": non logical value detected"); + Fill (Quot, 'X'); + return Quot; + end if; + if R0 = '0' then + Error_Msg_Synth (+Loc, "NUMERIC_STD.""/"": division by 0"); + Fill (Quot, 'X'); + return Quot; + end if; + Divmod (L, R, Quot, Null_Memtyp); + return Quot; + end Div_Uns_Uns; + + function Div_Sgn_Sgn (L, R : Memtyp; Loc : Syn_Src) return Memtyp + is + Nlen : constant Uns32 := L.Typ.Vbound.Len; + Dlen : constant Uns32 := R.Typ.Vbound.Len; + Quot : Memtyp; + R0 : Sl_X01; + Lu : Memtyp; + Ru : Memtyp; + Neg : Boolean; + begin + Quot.Typ := Create_Res_Type (L.Typ, Nlen); + Quot := Create_Memory (Quot.Typ); + if Nlen = 0 or Dlen = 0 then + return Quot; + end if; + + R0 := Has_0x (R); + if Has_0x (L) = 'X' or R0 = 'X' then + Warning_Msg_Synth + (+Loc, "NUMERIC_STD.""/"": non logical value detected"); + Fill (Quot, 'X'); + return Quot; + end if; + if R0 = '0' then + Error_Msg_Synth (+Loc, "NUMERIC_STD.""/"": division by 0"); + Fill (Quot, 'X'); + return Quot; + 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 + Lu := 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); + Neg := not Neg; + else + Ru := R; + end if; + + Divmod (Lu, Ru, Quot, Null_Memtyp); + + if Neg then + Neg_Vec (Quot); + end if; + return Quot; + end Div_Sgn_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 7254d636f..2a75fe8b6 100644 --- a/src/synth/synth-ieee-numeric_std.ads +++ b/src/synth/synth-ieee-numeric_std.ads @@ -61,6 +61,10 @@ package Synth.Ieee.Numeric_Std is function Mul_Int_Sgn (L : Int64; R : Memtyp; Loc : Syn_Src) return Memtyp; function Mul_Sgn_Int (L : Memtyp; R : Int64; Loc : Syn_Src) return Memtyp; + -- "/" + function Div_Uns_Uns (L, R : Memtyp; Loc : Syn_Src) return Memtyp; + function Div_Sgn_Sgn (L, R : Memtyp; Loc : Syn_Src) return Memtyp; + -- Shift function Shift_Vec (Val : Memtyp; Amt : Uns32; diff --git a/src/synth/synth-objtypes.ads b/src/synth/synth-objtypes.ads index 2e74db6dc..36a1b64cb 100644 --- a/src/synth/synth-objtypes.ads +++ b/src/synth/synth-objtypes.ads @@ -286,6 +286,7 @@ package Synth.Objtypes is function Create_Memory_Discrete (Val : Int64; Vtype : Type_Acc) return Memtyp; + function Alloc_Memory (Vtype : Type_Acc) return Memory_Ptr; function Create_Memory (Vtype : Type_Acc) return Memtyp; function Is_Equal (L, R : Memtyp) return Boolean; diff --git a/src/synth/synth-static_oper.adb b/src/synth/synth-static_oper.adb index b5ceee009..282d316cf 100644 --- a/src/synth/synth-static_oper.adb +++ b/src/synth/synth-static_oper.adb @@ -562,6 +562,11 @@ package body Synth.Static_Oper is when Iir_Predefined_Ieee_Numeric_Std_Mul_Int_Sgn => return Mul_Int_Sgn (Read_Discrete (Left), Right, Expr); + when Iir_Predefined_Ieee_Numeric_Std_Div_Uns_Uns => + return Div_Uns_Uns (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_Srl_Uns_Int | Iir_Predefined_Ieee_Numeric_Std_Srl_Sgn_Int => declare |