aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/openieee/build_numeric.py
diff options
context:
space:
mode:
authorTristan Gingold <gingold@adacore.com>2015-12-03 21:04:42 +0100
committerTristan Gingold <gingold@adacore.com>2015-12-16 09:35:28 +0100
commit8d5c9a328a7285c5457bf8fdfcb403b87db1e263 (patch)
tree8b9898f2f82b1413040472476174e5ea7644064b /libraries/openieee/build_numeric.py
parent8cc62e1063ed2ba035e9ca7ed7667c8fca319e6b (diff)
downloadghdl-8d5c9a328a7285c5457bf8fdfcb403b87db1e263.tar.gz
ghdl-8d5c9a328a7285c5457bf8fdfcb403b87db1e263.tar.bz2
ghdl-8d5c9a328a7285c5457bf8fdfcb403b87db1e263.zip
openieee: add numeric_std and numeric_bit.
Diffstat (limited to 'libraries/openieee/build_numeric.py')
-rwxr-xr-xlibraries/openieee/build_numeric.py1112
1 files changed, 1112 insertions, 0 deletions
diff --git a/libraries/openieee/build_numeric.py b/libraries/openieee/build_numeric.py
new file mode 100755
index 000000000..a8914d0ce
--- /dev/null
+++ b/libraries/openieee/build_numeric.py
@@ -0,0 +1,1112 @@
+#!/usr/bin/env python
+# Generate the body of ieee.numeric_std and numeric_bit from a template.
+# The implementation is based only on the specification and on testing (as
+# the specifications are often ambiguous).
+# The algorithms are very simple: carry ripple adder, restoring division.
+# This file is part of GHDL.
+# Both this file and the outputs of this file are copyrighted.
+# Copyright (C) 2015 Tristan Gingold
+#
+# GHDL 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, or (at your option) any later
+# version.
+#
+# GHDL 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 GCC; see the file COPYING2. If not see
+# <http://www.gnu.org/licenses/>.
+
+import re
+import sys
+
+# My python 'style' and knowledge is basic... Do not hesitate to comment.
+
+binary_funcs = [ "and", "nand", "or", "nor", "xor" ]
+compare_funcs = [ "=", "/=", ">", ">=", "<", "<=" ]
+
+vec_types = ['UNSIGNED', 'SIGNED']
+
+logics = ['bit', 'std']
+logic_types = {'bit' : 'bit', 'std': 'sl_x01' }
+logic_undefs = {'bit' : "'0'", 'std': "'X'" }
+
+logic = 'xx' # Current logic, either bit or std
+
+# Stream to write.
+out=sys.stdout
+
+def w(s):
+ "Write S to the output"
+ out.write(s)
+
+def logic_type():
+ return logic_types[logic]
+
+def logic_undef():
+ return logic_undefs[logic]
+
+def disp_vec_binary(func, typ):
+ "Generate the body of a vector binary logic function"
+ res = """
+ function "{0}" (l, r : {1}) return {1}
+ is
+ subtype res_type is {1} (l'length - 1 downto 0);
+ alias la : res_type is l;
+ alias ra : {1} (r'length - 1 downto 0) is r;
+ variable res : res_type;
+ begin
+ if la'left /= ra'left then
+ assert false
+ report "NUMERIC_STD.""{0}"": arguments are not of the same length"
+ severity failure;
+ res := (others => """ + logic_undef() + """);
+ else
+ for I in res_type'range loop
+ res (I) := la (I) {0} ra (I);
+ end loop;
+ end if;
+ return res;
+ end "{0}";\n"""
+ w (res.format(func, typ))
+
+def disp_non_logical_warning(func):
+ return """
+ assert NO_WARNING
+ report "NUMERIC_STD.""{0}"": non logical value detected"
+ severity warning;""".format(func)
+
+def conv_bit(expr):
+ if logic == 'std':
+ return "sl_to_x01 (" + expr + ")"
+ else:
+ return expr
+
+def extract_bit(name):
+ res = "{0}b := " + conv_bit ("{0}a (i)") + ";"
+ return res.format(name)
+
+def init_carry(func):
+ if func == '+':
+ return """
+ carry := '0';"""
+ else:
+ return """
+ carry := '1';"""
+
+def extract_extend_bit(name,typ):
+ res = """
+ if i > {0}a'left then
+ {0}b := """
+ if typ == 'UNSIGNED':
+ res += "'0';"
+ else:
+ res += "{0} ({0}'left);"
+ res += """
+ else
+ """ + extract_bit(name) + """
+ end if;"""
+ return res.format(name)
+
+def disp_vec_vec_binary(func, typ):
+ "Generate vector binary function body"
+ res = """
+ function "{0}" (l : {1}; r : {1}) return {1}
+ is
+ constant lft : integer := MAX (l'length, r'length) - 1;
+ subtype res_type is {1} (lft downto 0);
+ alias la : {1} (l'length - 1 downto 0) is l;
+ alias ra : {1} (r'length - 1 downto 0) is r;
+ variable res : res_type;
+ variable lb, rb, carry : """ + logic_type () + """;
+ begin
+ if la'left < 0 or ra'left < 0 then
+ return null_{1};
+ end if;"""
+
+ res += init_carry(func)
+
+ res += """
+ for i in 0 to lft loop"""
+ res += extract_extend_bit('l', typ)
+ res += extract_extend_bit('r', typ)
+
+ if logic == 'std':
+ res += """
+ if lb = 'X' or rb = 'X' then""" + \
+ disp_non_logical_warning(func) + """
+ res := (others => 'X');
+ exit;
+ end if;"""
+ if func == '-':
+ res += """
+ rb := not rb;"""
+ res += """
+ res (i) := compute_sum (carry, rb, lb);
+ carry := compute_carry (carry, rb, lb);
+ end loop;
+ return res;
+ end "{0}";
+"""
+ w (res.format (func, typ))
+
+def declare_int_var(name, typ):
+ res = """
+ variable {0}1, {0}2 : {1};
+ variable {0}d : nat1;""";
+ if typ == "INTEGER":
+ res += """
+ constant {0}msb : nat1 := boolean'pos({0} < 0);"""
+ return res.format(name, typ)
+
+def init_int_var(name, typ):
+ return """
+ {0}1 := {0};""".format(name);
+
+def extract_int_lsb(name, typ):
+ res = """
+ {0}2 := {0}1 / 2;"""
+ if typ == "INTEGER":
+ res += """
+ if {0}1 < 0 then
+ {0}d := 2 * {0}2 - {0}1;
+ {0}1 := {0}2 - {0}d;
+ else
+ {0}d := {0}1 - 2 * {0}2;
+ {0}1 := {0}2;
+ end if;"""
+ else:
+ res += """
+ {0}d := {0}1 - 2 * {0}2;
+ {0}1 := {0}2;"""
+ res += """
+ {0}b := nat1_to_01 ({0}d);"""
+ return res.format(name,typ)
+
+def check_int_truncated(func, name, typ):
+ if typ == "INTEGER":
+ v = "-{0}msb".format(name)
+ else:
+ v = "0"
+ return """
+ if {1}1 /= {2} then
+ assert NO_WARNING
+ report "NUMERIC_STD.""{0}"": vector is truncated"
+ severity warning;
+ end if;""".format(func, name, v)
+
+def create_vec_int_dict(func, left, right):
+ if left in vec_types:
+ dic = {'vtype': left,
+ 'itype': right,
+ 'vparam': 'l',
+ 'iparam': 'r'}
+ else:
+ dic = {'vtype': right,
+ 'itype': left,
+ 'vparam': 'r',
+ 'iparam': 'l'}
+ dic.update({'ltype': left,
+ 'rtype': right,
+ 'func': func,
+ 'logic': logic_type()})
+ return dic
+
+def disp_vec_int_binary(func, left, right):
+ "Generate vector binary function body"
+ dic = create_vec_int_dict(func, left, right)
+ res = """
+ function "{func}" (l : {ltype}; r : {rtype}) return {vtype}
+ is
+ subtype res_type is {vtype} ({vparam}'length - 1 downto 0);
+ alias {vparam}a : res_type is {vparam};""" + \
+ declare_int_var (dic["iparam"], dic["itype"]) + """
+ variable res : res_type;
+ variable lb, rb, carry : {logic};
+ begin
+ if res'length < 0 then
+ return null_{vtype};
+ end if;"""
+
+ # Initialize carry. For subtraction, use 2-complement.
+ res += init_carry(func)
+
+ res += init_int_var(dic['iparam'], dic['itype']) + """
+ for i in res'reverse_range loop
+ """ + extract_bit(dic['vparam']) + "\n" + \
+ extract_int_lsb(dic['iparam'], dic['itype']);
+
+ if logic == 'std':
+ res += """
+ if {vparam}b = 'X' then""" + \
+ disp_non_logical_warning(func) + """
+ res := (others => 'X');
+ {iparam}1 := 0;
+ exit;
+ end if;"""
+
+ # 2-complement for subtraction
+ if func == '-':
+ res += """
+ rb := not rb;"""
+
+ res += """
+ res (i) := compute_sum (carry, rb, lb);
+ carry := compute_carry (carry, rb, lb);
+ end loop;""" + \
+ check_int_truncated(func, dic['iparam'], dic['itype']) + """
+ return res;
+ end "{func}";\n"""
+ w(res.format (**dic))
+
+def disp_vec_int_gcompare(func, left, right):
+ "Generate comparison function"
+ dic = create_vec_int_dict(func, left, right)
+ res = """
+ function {func} (l : {ltype}; r : {rtype}) return compare_type
+ is
+ subtype res_type is {vtype} ({vparam}'length - 1 downto 0);
+ alias la : res_type is l;""" + \
+ declare_int_var (dic['iparam'], dic['itype']) + """
+ variable lb, rb : {logic};
+ variable res : compare_type;
+ begin
+ res := compare_eq;""";
+
+ res += init_int_var(dic['iparam'], dic['itype']) + """
+ for i in {vparam}a'reverse_range loop
+ """ + extract_bit (dic['vparam']) + \
+ extract_int_lsb("r", right)
+
+ if logic == 'std':
+ res += """
+ if {vparam}b = 'X' then
+ return compare_unknown;
+ end if;"""
+
+ res += """
+ if lb = '1' and rb = '0' then
+ res := compare_gt;
+ elsif lb = '0' and rb = '1' then
+ res := compare_lt;
+ end if;
+ end loop;"""
+ if func == "ucompare":
+ res += """
+ if r1 /= 0 then
+ res := compare_lt;
+ end if;"""
+ else:
+ res += """
+ if """ + conv_bit ("l (l'left)") + """ = '1' then
+ if r >= 0 then
+ res := compare_lt;
+ end if;
+ else
+ if r < 0 then
+ res := compare_gt;
+ end if;
+ end if;"""
+ res += """
+ return res;
+ end {func};
+"""
+ w(res.format (**dic))
+
+def disp_vec_int_compare(func, left, right):
+ "Generate comparison function"
+ dic = create_vec_int_dict(func, left, right)
+ res = """
+ function "{func}" (l : {ltype}; r : {rtype}) return boolean
+ is
+ subtype res_type is {vtype} ({vparam}'length - 1 downto 0);
+ alias {vparam}a : res_type is {vparam};""" + \
+ declare_int_var (dic['iparam'], dic['itype']) + """
+ variable res : compare_type;
+ begin
+ if {vparam}'length = 0 then
+ assert NO_WARNING
+ report "NUMERIC_STD.""{func}"": null argument, returning FALSE"
+ severity warning;
+ return false;
+ end if;
+
+ res := """
+
+ if left == "SIGNED" or right == "SIGNED":
+ res += "scompare"
+ else:
+ res += "ucompare"
+ if left in vec_types:
+ res += " (l, r);"
+ else:
+ res += " (r, l);"
+ if logic == 'std':
+ res += """
+ if res = compare_unknown then""" + \
+ disp_non_logical_warning(func) + """
+ return false;
+ end if;"""
+
+ if left in vec_types:
+ res += """
+ return res {func} compare_eq;"""
+ else:
+ res += """
+ return compare_eq {func} res;"""
+ res += """
+ end "{func}";
+"""
+ w(res.format (**dic))
+
+def disp_vec_vec_gcompare(func, typ):
+ "Generate comparison function"
+ res = """
+ function {func} (l : {typ}; r : {typ}) return compare_type
+ is
+ constant sz : integer := MAX (l'length, r'length) - 1;
+ alias la : {typ} (l'length - 1 downto 0) is l;
+ alias ra : {typ} (r'length - 1 downto 0) is r;
+ variable lb, rb : {logic};
+ variable res : compare_type;
+ begin"""
+ if typ == 'SIGNED':
+ res += """
+ -- Consider sign bit as S * -(2**N).
+ lb := """ + conv_bit ("la (la'left)") + """;
+ rb := """ + conv_bit ("ra (ra'left)") + """;
+ if lb = '1' and rb = '0' then
+ return compare_lt;
+ elsif lb = '0' and rb = '1' then
+ return compare_gt;
+ else
+ res := compare_eq;
+ end if;"""
+ else:
+ res += """
+ res := compare_eq;"""
+ if typ == 'SIGNED':
+ res += """
+ for i in 0 to sz - 1 loop"""
+ else:
+ res += """
+ for i in 0 to sz loop"""
+ res += extract_extend_bit('l', typ)
+ res += extract_extend_bit('r', typ)
+ if logic == 'std':
+ res += """
+ if lb = 'X' or rb = 'X' then
+ return compare_unknown;
+ end if;"""
+
+ res += """
+ if lb = '1' and rb = '0' then
+ res := compare_gt;
+ elsif lb = '0' and rb = '1' then
+ res := compare_lt;
+ end if;
+ end loop;
+
+ return res;
+ end {func};\n"""
+ w(res.format (func=func, typ=typ, logic=logic_type()))
+
+def disp_vec_vec_compare(func, typ):
+ "Generate comparison function"
+ res = """
+ function "{func}" (l : {typ}; r : {typ}) return boolean
+ is
+ variable res : compare_type;
+ begin
+ if l'length = 0 or r'length = 0 then
+ assert NO_WARNING
+ report "NUMERIC_STD.""{func}"": null argument, returning FALSE"
+ severity warning;
+ return false;
+ end if;
+
+ res := """
+ if typ == "SIGNED":
+ res += "scompare"
+ else:
+ res += "ucompare"
+ res += """ (l, r);"""
+
+ if logic == 'std':
+ res += """
+ if res = compare_unknown then""" + \
+ disp_non_logical_warning(func) + """
+ return false;
+ end if;"""
+
+ res += """
+ return res {func} compare_eq;
+ end "{func}";\n"""
+ w(res.format (func=func, typ=typ))
+
+def disp_vec_not(typ):
+ "Generate vector binary function body"
+ w("""
+ function "not" (l : {0}) return {0}
+ is
+ subtype res_type is {0} (l'length - 1 downto 0);
+ alias la : res_type is l;
+ variable res : res_type;
+ begin
+ for I in res_type'range loop
+ res (I) := not la (I);
+ end loop;
+ return res;
+ end "not";\n""".format(typ))
+
+def disp_resize(typ):
+ res = """
+ function resize (ARG : {0}; NEW_SIZE: natural) return {0}
+ is
+ alias arg1 : {0} (ARG'length - 1 downto 0) is arg;
+ variable res : {0} (new_size - 1 downto 0) := (others => '0');
+ begin
+ if new_size = 0 then
+ return null_{0};
+ end if;
+ if arg1'length = 0 then
+ return res;
+ end if;
+ if arg1'length > new_size then
+ -- Reduction."""
+ if typ == 'SIGNED':
+ res += """
+ res (res'left) := arg1 (arg1'left);
+ res (res'left - 1 downto 0) := arg1 (res'left - 1 downto 0);"""
+ else:
+ res += """
+ res := arg1 (res'range);"""
+ res += """
+ else
+ -- Expansion
+ res (arg1'range) := arg1;"""
+ if typ == 'SIGNED':
+ res += """
+ res (res'left downto arg1'length) := (others => arg1 (arg1'left));"""
+ res += """
+ end if;
+ return res;
+ end resize;\n"""
+ w(res.format(typ))
+
+def disp_shift(name, typ, dir):
+ res = """
+ function {0} (ARG : {1}; COUNT: NATURAL) return {1}
+ is
+ subtype res_type is {1} (ARG'length - 1 downto 0);
+ alias arg1 : res_type is arg;
+ variable res : res_type := (others => """
+ if typ == 'SIGNED' and dir == 'right':
+ res += "arg1 (arg1'left)"
+ else:
+ res += "'0'"
+ res += """);
+ begin
+ if res'length = 0 then
+ return null_{1};
+ end if;
+ if count <= arg1'left then"""
+ if dir == 'left':
+ res += """
+ res (res'left downto count) := arg1 (arg1'left - count downto 0);"""
+ else:
+ res += """
+ res (res'left - count downto 0) := arg1 (arg1'left downto count);"""
+ res += """
+ end if;
+ return res;
+ end {0};\n"""
+ w(res.format(name, typ))
+
+def disp_rotate(name, typ, dir):
+ res = """
+ function {0} (ARG : {1}; COUNT: NATURAL) return {1}
+ is
+ subtype res_type is {1} (ARG'length - 1 downto 0);
+ alias arg1 : res_type is arg;
+ variable res : res_type := (others => '0');
+ variable cnt : natural;
+ begin
+ if res'length = 0 then
+ return null_{1};
+ end if;
+ cnt := count rem res'length;"""
+ if dir == 'left':
+ res += """
+ res (res'left downto cnt) := arg1 (res'left - cnt downto 0);
+ res (cnt - 1 downto 0) := arg1 (res'left downto res'left - cnt + 1);"""
+ else:
+ res += """
+ res (res'left - cnt downto 0) := arg1 (res'left downto cnt);
+ res (res'left downto res'left - cnt + 1) := arg1 (cnt - 1 downto 0);"""
+ res += """
+ return res;
+ end {0};\n"""
+ w(res.format(name, typ))
+
+def disp_vec_vec_mul(func, typ):
+ res = """
+ function "{0}" (L : {1}; R : {1}) return {1}
+ is
+ alias la : {1} (L'Length - 1 downto 0) is l;
+ alias ra : {1} (R'Length - 1 downto 0) is r;
+ variable res : {1} (L'length + R'Length -1 downto 0) := (others => '0');
+ variable rb, lb, vb, carry : """ + logic_type() + """;
+ begin
+ if la'length = 0 or ra'length = 0 then
+ return null_{1};
+ end if;
+ -- Shift and add L.
+ for i in natural range 0 to ra'left """
+ if typ == 'SIGNED':
+ res += "- 1 "
+ res += """loop
+ """ + extract_bit ('r') + """
+ if rb = '1' then
+ -- Compute res := res + shift_left (l, i).
+ carry := '0';
+ for j in la'reverse_range loop
+ lb := la (j);
+ vb := res (i + j);
+ res (i + j) := compute_sum (carry, vb, lb);
+ carry := compute_carry (carry, vb, lb);
+ end loop;"""
+ if typ == 'UNSIGNED':
+ res += """
+ -- Propagate carry.
+ for j in i + la'length to res'left loop
+ exit when carry = '0';
+ vb := res (j);
+ res (j) := carry xor vb;
+ carry := carry and vb;
+ end loop;"""
+ else:
+ res += """
+ -- Sign extend and propagate carry.
+ lb := la (la'left);
+ for j in i + l'length to res'left loop
+ vb := res (j);
+ res (j) := compute_sum (carry, vb, lb);
+ carry := compute_carry (carry, vb, lb);
+ end loop;"""
+ if logic == 'std':
+ res += """
+ elsif rb = 'X' then""" + \
+ disp_non_logical_warning (func)
+ res += """
+ end if;
+ end loop;"""
+ if typ == 'SIGNED':
+ res += """
+ if ra (ra'left) = '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 la'reverse_range loop
+ vb := res (ra'length - 1 + i);
+ lb := not la (i);
+ res (ra'length - 1+ i) := compute_sum (carry, vb, lb);
+ carry := compute_carry (carry, vb, lb);
+ end loop;
+ vb := res (res'left);
+ lb := not la (la'left);
+ res (res'left) := compute_sum (carry, vb, lb);
+ end if;"""
+ res += """
+ return res;
+ end "{0}";\n"""
+ w(res.format(func,typ))
+
+def disp_vec_int_mul(left, right):
+ res = """
+ function "*" (L : {0}; R : {1}) return {0}
+ is
+ constant size : natural := l'length;
+ begin
+ if size = 0 then
+ return null_{0};
+ end if;
+ return l * to_{0} (r, size);
+ end "*";\n"""
+ w (res.format(left,right))
+
+def disp_int_vec_mul(left, right):
+ res = """
+ function "*" (L : {0}; R : {1}) return {1}
+ is
+ constant size : natural := r'length;
+ begin
+ if size = 0 then
+ return null_{1};
+ end if;
+ return r * to_{1} (l, size);
+ end "*";\n"""
+ w (res.format(left,right))
+
+def disp_neg(func):
+ res = """
+ function "{func}" (ARG : SIGNED) return SIGNED
+ is
+ subtype arg_type is SIGNED (ARG'length - 1 downto 0);
+ alias arga : arg_type is arg;
+ variable res : arg_type;
+ variable carry, a : """ + logic_type() + """;
+ begin
+ if arga'length = 0 then
+ return null_signed;
+ end if;"""
+ if logic == 'std':
+ res += """
+ if has_0x (arga) = 'X' then""" + \
+ disp_non_logical_warning("-") + """
+ return arg_type'(others => 'X');
+ end if;"""
+ if func == 'abs':
+ res += """
+ if arga (arga'left) = '0' then
+ return arga;
+ end if;"""
+ res += """
+ carry := '1';
+ for i in arga'reverse_range loop
+ a := not arga (i);
+ res (i) := carry xor a;
+ carry := carry and a;
+ end loop;
+ return res;
+ end "{func}";\n"""
+ w(res.format(func=func))
+
+def disp_has_0x(typ):
+ res = """
+ function has_0x (a : {0}) return {1}
+ is
+ variable res : {1} := '0';
+ begin
+ for i in a'range loop"""
+ if logic == 'std':
+ res += """
+ if a (i) = 'X' then
+ return 'X';
+ end if;"""
+ res += """
+ res := res or a (i);
+ end loop;
+ return res;
+ end has_0x;\n"""
+ w(res.format(typ, logic_type()))
+
+def disp_size():
+ w("""
+ function size_unsigned (n : natural) return natural
+ is
+ -- At least one bit (even for 0).
+ variable res : natural := 1;
+ variable n1 : natural := n;
+ begin
+ while n1 > 1 loop
+ res := res + 1;
+ n1 := n1 / 2;
+ end loop;
+ return res;
+ end size_unsigned;\n""")
+
+ w("""
+ function size_signed (n : integer) return natural
+ is
+ variable res : natural := 1;
+ variable n1 : natural;
+ begin
+ if n >= 0 then
+ n1 := n;
+ else
+ -- Use /N = -X -1 = -(X + 1) (No overflow).
+ n1 := -(n + 1);
+ end if;
+ while n1 /= 0 loop
+ res := res + 1;
+ n1 := n1 / 2;
+ end loop;
+ return res;
+ end size_signed;\n""")
+
+def disp_divmod():
+ w("""
+ -- All index range are normalized (N downto 0).
+ -- NUM and QUOT have the same range.
+ -- DEM and REMAIN have the same range.
+ -- No 'X'.
+ procedure divmod (num, dem : UNSIGNED; quot, remain : out UNSIGNED)
+ is
+ variable reg : unsigned (dem'left + 1 downto 0) := (others => '0');
+ variable sub : unsigned (dem'range) := (others => '0');
+ variable carry, d : """ + logic_type () + """;
+ begin
+ for i in num'range loop
+ -- Shift
+ reg (reg'left downto 1) := reg (reg'left - 1 downto 0);
+ reg (0) := num (i);
+ -- Substract
+ carry := '1';
+ for j in dem'reverse_range loop
+ d := not dem (j);
+ sub (j) := compute_sum (carry, reg (j), d);
+ carry := compute_carry (carry, reg (j), d);
+ end loop;
+ carry := compute_carry (carry, reg (reg'left), '1');
+ -- Test
+ if carry = '0' then
+ -- Greater than
+ quot (i) := '0';
+ else
+ quot (i) := '1';
+ reg (reg'left) := '0';
+ reg (sub'range) := sub;
+ end if;
+ end loop;
+ remain := reg (dem'range);
+ end divmod;
+ """)
+
+def disp_vec_vec_udiv(func):
+ res = """
+ function "{func}" (L : UNSIGNED; R : UNSIGNED) return UNSIGNED
+ is
+ subtype l_type is UNSIGNED (L'length - 1 downto 0);
+ subtype r_type is UNSIGNED (R'length - 1 downto 0);
+ alias la : l_type is l;
+ alias ra : r_type is r;
+ variable quot : l_type;
+ variable rema : r_type;
+ variable r0 : """ + logic_type() + """ := has_0x (r);
+ begin
+ if la'length = 0 or ra'length = 0 then
+ return null_unsigned;
+ end if;"""
+ if logic == 'std':
+ res += """
+ if has_0x (l) = 'X' or r0 = 'X' then""" + \
+ disp_non_logical_warning ('/') + """
+ return l_type'(others => 'X');
+ end if;"""
+ res += """
+ assert r0 /= '0'
+ report "NUMERIC_STD.""{func}"": division by 0"
+ severity error;
+ divmod (la, ra, quot, rema);"""
+ if func == '/':
+ res += """
+ return quot;"""
+ else:
+ res += """
+ return rema;"""
+ res += """
+ end "{func}";\n"""
+ w(res.format(func=func))
+
+def disp_vec_int_udiv(func):
+ res = """
+ function "{func}" (L : UNSIGNED; R : NATURAL) return UNSIGNED
+ is
+ constant r_size : natural := size_unsigned (r);
+ begin
+ if l'length = 0 then
+ return null_unsigned;
+ end if;"""
+ if func in ['mod', 'rem']:
+ res += """
+ return resize (l {func} to_unsigned (r, r_size), l'length);"""
+ else:
+ res += """
+ return l {func} to_unsigned (r, r_size);"""
+ res += """
+ end "{func}";\n"""
+ w(res.format(func=func))
+
+ res = """
+ function "{func}" (L : NATURAL; R : UNSIGNED) return UNSIGNED
+ is
+ constant l_size : natural := size_unsigned (l);
+ begin
+ if r'length = 0 then
+ return null_unsigned;
+ end if;"""
+ if func == '/':
+ res += """
+ return resize (to_unsigned (l, l_size) {func} r, r'length);"""
+ else:
+ res += """
+ return to_unsigned (l, l_size) {func} r;"""
+ res += """
+ end "{func}";\n"""
+ w(res.format(func=func))
+
+def disp_vec_vec_sdiv(func):
+ res = """
+ function "{func}" (L : SIGNED; R : SIGNED) return SIGNED
+ is
+ subtype l_type is SIGNED (L'length - 1 downto 0);
+ subtype r_type is SIGNED (R'length - 1 downto 0);
+ alias la : l_type is l;
+ alias ra : r_type is r;
+ subtype l_utype is UNSIGNED (l_type'range);
+ subtype r_utype is UNSIGNED (r_type'range);
+ variable lu : l_utype;
+ variable ru : r_utype;
+ variable quot : l_utype;
+ variable rema : r_utype;
+ variable r0 : """ + logic_type() + """ := has_0x (r);
+ begin
+ if la'length = 0 or ra'length = 0 then
+ return null_signed;
+ end if;"""
+ if logic == 'std':
+ res += """
+ if has_0x (l) = 'X' or r0 = 'X' then""" + \
+ disp_non_logical_warning (func) + """
+ return l_type'(others => 'X');
+ end if;"""
+ res += """
+ assert r0 /= '0'
+ report "NUMERIC_STD.""{func}"": division by 0"
+ severity error;"""
+ res += """
+ if la (la'left) = '1' then
+ lu := unsigned (-la);
+ else
+ lu := unsigned (la);
+ end if;
+ if ra (ra'left) = '1' then
+ ru := unsigned (-ra);
+ else
+ ru := unsigned (ra);
+ end if;
+ divmod (lu, ru, quot, rema);"""
+ if func == '/':
+ res += """
+ if (ra (ra'left) xor la (la'left)) = '1' then
+ return -signed (quot);
+ else
+ return signed (quot);
+ end if;"""
+ elif func == 'rem':
+ res += """
+ -- Result of rem has the sign of the dividend.
+ if la (la'left) = '1' then
+ return -signed (rema);
+ else
+ return signed (rema);
+ end if;"""
+ elif func == 'mod':
+ res += """
+ -- Result of mod has the sign of the divisor.
+ if rema = r_utype'(others => '0') then
+ -- If the remainder is 0, then the modulus is 0.
+ return signed (rema);
+ else
+ if ra (ra'left) = '1' then
+ if la (la'left) = '1' then
+ return -signed (rema);
+ else
+ return ra + signed (rema);
+ end if;
+ else
+ if la (la'left) = '1' then
+ return ra - signed (rema);
+ else
+ return signed (rema);
+ end if;
+ end if;
+ end if;"""
+ res += """
+ end "{func}";\n"""
+ w(res.format(func=func))
+
+def disp_vec_int_sdiv(func):
+ res = """
+ function "{func}" (L : SIGNED; R : INTEGER) return SIGNED
+ is
+ constant r_size : natural := size_signed (r);
+ begin
+ if l'length = 0 then
+ return null_signed;
+ end if;"""
+ if func == '/':
+ res += """
+ return l {func} to_signed (r, r_size);"""
+ else:
+ res += """
+ return resize (l {func} to_signed (r, r_size), l'length);"""
+ res += """
+ end "{func}";\n"""
+ w(res.format(func=func))
+
+ res = """
+ function "{func}" (L : INTEGER; R : SIGNED) return SIGNED
+ is
+ constant l_size : natural := size_signed (l);
+ begin
+ if r'length = 0 then
+ return null_signed;
+ end if;"""
+ if func == '/':
+ res += """
+ return resize (to_signed (l, max (l_size, r'length)) {func} r, r'length);"""
+ else:
+ res += """
+ return to_signed (l, l_size) {func} r;"""
+ res += """
+ end "{func}";\n"""
+ w(res.format(func=func))
+
+def disp_all_log_funcs():
+ "Generate all function bodies for logic operators"
+ for t in vec_types:
+ disp_resize(t)
+ for v in vec_types:
+ disp_vec_not(v)
+ for f in binary_funcs:
+ for v in vec_types:
+ disp_vec_binary(f, v)
+ disp_vec_vec_gcompare("ucompare", "UNSIGNED")
+ disp_vec_vec_gcompare("scompare", "SIGNED")
+ disp_vec_int_gcompare("ucompare", "UNSIGNED", "NATURAL")
+ disp_vec_int_gcompare("scompare", "SIGNED", "INTEGER")
+ for f in compare_funcs:
+ disp_vec_vec_compare(f, "UNSIGNED")
+ disp_vec_vec_compare(f, "SIGNED")
+ disp_vec_int_compare(f, "UNSIGNED", "NATURAL")
+ disp_vec_int_compare(f, "NATURAL", "UNSIGNED")
+ disp_vec_int_compare(f, "SIGNED", "INTEGER")
+ disp_vec_int_compare(f, "INTEGER", "SIGNED")
+ for t in vec_types:
+ for d in ['left', 'right']:
+ disp_shift('shift_' + d, t, d);
+ for d in ['left', 'right']:
+ disp_rotate('rotate_' + d, t, d);
+
+def disp_match(typ):
+ res = """
+ function std_match (l, r : {0}) return boolean
+ is
+ alias la : {0} (l'length downto 1) is l;
+ alias ra : {0} (r'length downto 1) is r;
+ begin
+ if la'left = 0 or ra'left = 0 then
+ assert NO_WARNING
+ report "NUMERIC_STD.STD_MATCH: null argument, returning false"
+ severity warning;
+ return false;
+ elsif la'left /= ra'left then
+ assert NO_WARNING
+ report "NUMERIC_STD.STD_MATCH: args length mismatch, returning false"
+ severity warning;
+ return false;
+ else
+ for i in la'range loop
+ if not match_table (la (i), ra (i)) then
+ return false;
+ end if;
+ end loop;
+ return true;
+ end if;
+ end std_match;\n"""
+ w(res.format(typ))
+
+
+def disp_all_match_funcs():
+ disp_match('std_ulogic_vector');
+ disp_match('std_logic_vector');
+ disp_match('UNSIGNED');
+ disp_match('SIGNED');
+
+def disp_all_arith_funcs():
+ "Generate all function bodies for logic operators"
+ for op in ['+', '-']:
+ disp_vec_vec_binary(op, "UNSIGNED")
+ disp_vec_vec_binary(op, "SIGNED")
+ disp_vec_int_binary(op, "UNSIGNED", "NATURAL")
+ disp_vec_int_binary(op, "NATURAL", "UNSIGNED")
+ disp_vec_int_binary(op, "SIGNED", "INTEGER")
+ disp_vec_int_binary(op, "INTEGER", "SIGNED")
+ disp_vec_vec_mul('*', 'UNSIGNED')
+ disp_vec_vec_mul('*', 'SIGNED')
+ disp_vec_int_mul('UNSIGNED', 'NATURAL')
+ disp_vec_int_mul('SIGNED', 'INTEGER')
+ disp_int_vec_mul('NATURAL', 'UNSIGNED')
+ disp_int_vec_mul('INTEGER', 'SIGNED')
+ disp_has_0x('UNSIGNED')
+ disp_divmod()
+ disp_size()
+ disp_vec_vec_udiv('/')
+ disp_vec_int_udiv('/')
+ disp_vec_vec_udiv('rem')
+ disp_vec_int_udiv('rem')
+ disp_vec_vec_udiv('mod')
+ disp_vec_int_udiv('mod')
+ disp_has_0x('SIGNED')
+ disp_neg("-")
+ disp_neg("abs")
+ disp_vec_vec_sdiv('/')
+ disp_vec_int_sdiv('/')
+ disp_vec_vec_sdiv('rem')
+ disp_vec_int_sdiv('rem')
+ disp_vec_vec_sdiv('mod')
+ disp_vec_int_sdiv('mod')
+
+# Patterns to replace
+pats = {' @LOG\n' : disp_all_log_funcs,
+ ' @ARITH\n' : disp_all_arith_funcs,
+ ' @MATCH\n' : disp_all_match_funcs }
+
+spec_file='numeric_std.vhdl'
+#proto_file='numeric_std-body.proto'
+
+def gen_body(proto_file):
+ w('-- This -*- vhdl -*- file was generated from ' + proto_file + '\n')
+ for line in open(proto_file):
+ if line in pats:
+ pats[line]()
+ continue
+ w(line)
+
+# Copy spec
+for log in logics:
+ for std in ['87', '93']:
+ out=open('numeric_' + log + '.v' + std, 'w')
+ for line in open('numeric_' + log + '.proto'):
+ if line == ' @COMMON\n':
+ for lcom in open('numeric_common.proto'):
+ if lcom[0:2] == '--':
+ pass
+ elif std == '87' and '"xnor"' in lcom:
+ w("--" + lcom[2:])
+ else:
+ w(lcom)
+ else:
+ w(line)
+ out.close()
+
+# Generate bodies
+for l in logics:
+ logic = l
+ out=open('numeric_{0}-body.v87'.format(l), 'w')
+ gen_body('numeric_{0}-body.proto'.format(l))
+ out.close()
+
+binary_funcs.append("xnor")
+for l in logics:
+ logic = l
+ out=open('numeric_{0}-body.v93'.format(l), 'w')
+ gen_body('numeric_{0}-body.proto'.format(l))
+ out.close()