aboutsummaryrefslogtreecommitdiffstats
path: root/src/synth/synth-ieee-utils.adb
diff options
context:
space:
mode:
Diffstat (limited to 'src/synth/synth-ieee-utils.adb')
-rw-r--r--src/synth/synth-ieee-utils.adb183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/synth/synth-ieee-utils.adb b/src/synth/synth-ieee-utils.adb
new file mode 100644
index 000000000..db1a48d71
--- /dev/null
+++ b/src/synth/synth-ieee-utils.adb
@@ -0,0 +1,183 @@
+-- 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 <gnu.org/licenses>.
+
+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;