1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
-- This -*- vhdl -*- file is part of GHDL.
-- IEEE 1076.3 compliant numeric bit package body.
-- The implementation is based only on the specifications.
-- Copyright (C) 2015-2021 Tristan Gingold
--
-- 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 NUMERIC_BIT is
constant NO_WARNING : Boolean := False;
constant null_unsigned : unsigned (0 downto 1) := (others => '0');
constant null_signed : signed (0 downto 1) := (others => '0');
subtype nat1 is natural range 0 to 1;
type nat1_to_sl_type is array (nat1) of bit;
constant nat1_to_01 : nat1_to_sl_type := (0 => '0', 1 => '1');
subtype sl_01 is bit;
type carry_array is array (sl_01, sl_01, sl_01) of sl_01;
constant compute_carry : carry_array :=
('0' => ('0' => ('0' => '0', '1' => '0'),
'1' => ('0' => '0', '1' => '1')),
'1' => ('0' => ('0' => '0', '1' => '1'),
'1' => ('0' => '1', '1' => '1')));
constant compute_sum : carry_array :=
('0' => ('0' => ('0' => '0', '1' => '1'),
'1' => ('0' => '1', '1' => '0')),
'1' => ('0' => ('0' => '1', '1' => '0'),
'1' => ('0' => '0', '1' => '1')));
type compare_type is (compare_unknown,
compare_lt,
compare_eq,
compare_gt);
function MAX (L, R : natural) return natural is
begin
if L > R then
return L;
else
return R;
end if;
end MAX;
function TO_INTEGER (ARG : UNSIGNED) return NATURAL
is
variable res : natural := 0;
begin
if arg'length = 0 then
assert NO_WARNING
report "NUMERIC_BIT.TO_INTEGER: null array detected, returning 0"
severity warning;
return 0;
end if;
for i in arg'range loop
res := res + res;
if arg (i) = '1' then
res := res + 1;
end if;
end loop;
return res;
end TO_INTEGER;
function TO_INTEGER (ARG : SIGNED) return INTEGER
is
alias argn : SIGNED (ARG'Length -1 downto 0) is arg;
variable res : integer := 0;
variable b : bit;
begin
if argn'length = 0 then
assert NO_WARNING
report "NUMERIC_BIT.TO_INTEGER: null array detected, returning 0"
severity warning;
return 0;
end if;
if argn (argn'left) = '1' then
-- Negative value
b := '0';
else
b := '1';
end if;
for i in argn'range loop
res := res + res;
if argn (i) = b then
res := res + 1;
end if;
end loop;
if b = '0' then
-- Avoid overflow.
res := -res - 1;
end if;
return res;
end TO_INTEGER;
function TO_UNSIGNED (ARG, SIZE : NATURAL) return UNSIGNED
is
variable res : UNSIGNED (SIZE - 1 downto 0);
variable a : natural := arg;
variable d : nat1;
begin
if size = 0 then
return null_unsigned;
end if;
for i in res'reverse_range loop
d := a rem 2;
res (i) := nat1_to_01 (d);
a := a / 2;
end loop;
if a /= 0 then
assert NO_WARNING
report "NUMERIC_BIT.TO_UNSIGNED: vector is truncated"
severity warning;
end if;
return res;
end TO_UNSIGNED;
function TO_SIGNED (ARG : INTEGER; SIZE : NATURAL) return SIGNED
is
variable res : SIGNED (SIZE - 1 downto 0);
variable v : integer := arg;
variable b0, b1 : bit;
variable d : nat1;
begin
if size = 0 then
return null_signed;
end if;
if arg < 0 then
-- Use one complement to avoid overflow:
-- -v = (not v) + 1
-- not v = -v - 1
-- not v = -(v + 1)
v := -(arg + 1);
b0 := '1';
b1 := '0';
else
v := arg;
b0 := '0';
b1 := '1';
end if;
for i in res'reverse_range loop
d := v rem 2;
v := v / 2;
if d = 0 then
res (i) := b0;
else
res (i) := b1;
end if;
end loop;
if v /= 0 or res (res'left) /= b0 then
assert NO_WARNING
report "NUMERIC_BIT.TO_SIGNED: vector is truncated"
severity warning;
end if;
return res;
end TO_SIGNED;
@ARITH
@LOG
function rising_edge (signal s : bit) return boolean is
begin
return s'event and s = '1';
end rising_edge;
function falling_edge (signal s : bit) return boolean is
begin
return s'event and s = '0';
end falling_edge;
end NUMERIC_BIT;
|