-- Simple logic utilities for ieee.std_logic -- 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, see . package body Synth.Ieee.Utils is procedure Neg_Vec (Src : Memory_Ptr; Dst : Memory_Ptr; Len : Uns32) is Vb, Carry : Sl_X01; begin Carry := '1'; for I in 1 .. Len loop Vb := Sl_To_X01 (Read_Std_Logic (Src, Len - I)); Vb := Not_Table (Vb); Write_Std_Logic (Dst, Len - I, Xor_Table (Carry, Vb)); Carry := And_Table (Carry, Vb); end loop; end Neg_Vec; procedure Abs_Vec (Src : Memory_Ptr; Dst : Memory_Ptr; Len : Uns32) is begin if Len > 0 and then Sl_To_X01 (Read_Std_Logic (Src, 0)) = '1' then Neg_Vec (Src, Dst, Len); else for I in 1 .. Size_Type (Len) loop Write_U8 (Dst + (I - 1), Read_U8 (Src + (I - 1))); end loop; end if; end Abs_Vec; procedure Fill (Res : Memory_Ptr; Len : Uns32; V : Std_Ulogic) is begin for I in 1 .. Len loop Write_Std_Logic (Res, I - 1, V); end loop; end Fill; procedure Mul_Vec (L, R : Memory_Ptr; Llen, Rlen : Uns32; L_Sign, R_Sign : Boolean; Res : Memory_Ptr) is Res_Len : constant Uns32 := Llen + Rlen + Boolean'Pos (L_Sign xor R_Sign); Lb, Rb, Vb, Carry : Sl_X01; begin -- Check for 'X' in L. for I in 1 .. Llen loop if Read_Std_Logic (L, I - 1) = 'X' then Fill (Res, Res_Len, 'X'); return; end if; end loop; -- Init RES. Fill (Res, Res_Len, '0'); if Rlen = 0 then return; end if; -- Shift and add L. for I in 1 .. Rlen - Boolean'Pos (R_Sign) loop Rb := Sl_To_X01 (Read_Std_Logic (R, Rlen - I)); if Rb = '1' then -- Compute res := res + shift_left (l, i). Carry := '0'; for J in 1 .. Llen loop Lb := Read_Std_Logic (L, Llen - J); Vb := Read_Std_Logic (Res, Res_Len - (I + J - 1)); Write_Std_Logic (Res, Res_Len - (I + J - 1), Compute_Sum (Carry, Vb, Lb)); Carry := Compute_Carry (Carry, Vb, Lb); end loop; -- Propagate carry. if L_Sign then -- Sign extend. Lb := Read_Std_Logic (L, 0); else Lb := '0'; end if; for J in I + Llen .. Res_Len loop exit when Lb = '0' and Carry = '0'; Vb := Read_Std_Logic (Res, Res_Len - J); Write_Std_Logic (Res, Res_Len - J, Compute_Sum (Carry, Vb, Lb)); Carry := Compute_Carry (Carry, Vb, Lb); end loop; elsif Rb = 'X' then Fill (Res, Res_Len, 'X'); exit; end if; end loop; if R_Sign and then Read_Std_Logic (R, 0) = '1' then -- R is a negative number. It is considered as: -- -2**n + (Rn-1 Rn-2 ... R0). -- Compute res := res - 2**n * l. Carry := '1'; for I in 1 .. Llen loop -- Start at len - (rlen - 1) = llen + 1 Vb := Read_Std_Logic (Res, Llen - I + 1); Lb := Not_Table (Read_Std_Logic (L, Llen - I)); Write_Std_Logic (Res, Llen - I + 1, Compute_Sum (Carry, Vb, Lb)); Carry := Compute_Carry (Carry, Vb, Lb); end loop; -- The last bit. Vb := Read_Std_Logic (Res, 0); Lb := Not_Table (Read_Std_Logic (L, 0)); Write_Std_Logic (Res, 0, Compute_Sum (Carry, Vb, Lb)); end if; end Mul_Vec; function Compare_Bit (Lb, Rb : Sl_01; L_Sign, R_Sign : Boolean) return Order_Type is begin if Lb = '1' and Rb = '0' then if L_Sign then return Less; else return Greater; end if; elsif Lb = '0' and Rb = '1' then if R_Sign then return Greater; else return Less; end if; else return Equal; end if; end Compare_Bit; function Compare_Vec (L, R : Memory_Ptr; Llen, Rlen : Uns32; L_Sign, R_Sign : Boolean) return Order_Type is Lb, Rb : Sl_01; begin -- The sign. if L_Sign and Llen > 0 then Lb := Sl_To_01 (Read_Std_Logic (L, 0)); else Lb := '0'; end if; if R_Sign and Rlen > 0 then Rb := Sl_To_01 (Read_Std_Logic (R, 0)); else Rb := '0'; end if; if Lb /= Rb then return Compare_Bit (Lb, Rb, L_Sign, R_Sign); end if; -- Same sign. for I in reverse 1 .. Uns32'Max (Llen, Rlen) loop if I <= Llen then Lb := Sl_To_01 (Read_Std_Logic (L, Llen - I)); end if; if I <= Rlen then Rb := Sl_To_01 (Read_Std_Logic (R, Rlen - I)); end if; if Lb = '0' and Rb = '1' then return Less; elsif Lb = '1' and Rb = '0' then return Greater; end if; end loop; return Equal; end Compare_Vec; end Synth.Ieee.Utils;